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

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

FPGAの部屋

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

The Simple MicroBlaze Microcontroller 6(シミュレーション)

SMMの問題点はシミュレーションができないことだと思う。実機デバックはできるが、シミュレーションは出来ない。EDKを使えばできるのかもしれない?が、それではISEだけでシンプルに実装する目的と合わない。
という訳で、SMMの周辺回路をシミュレーションする簡単なSMMのバスモデルを作ってみた。言語はサンプルがVHDLだったので、VHDLで作った。ISE12.3を使用している。
SMM_noUART_sim_pack.vhdがSMMのWriteサイクルとReadサイクルを行う。と言っても、コードを見てもらえば、すぐわかるようにとても簡単だ。WriteはWR_ADDRにアドレス、WR_DATAにデータ、WR_BEにバイト・イネーブルをセットして、procedureをコールすれば、SMMのWriteサイクルが起動する。Readサイクルは、RD_ADDRにアドレス、RD_BEにバイト・イネーブルをセットすれば、RD_DATAにReadしたデータが出力される。下に、SMM_noUART_sim_pack.vhdを示す。ほとんど”procedureを使うときの注意点”のコードと同じ。

-- SMM_noUART用パッケージ

library ieee;
use ieee.std_logic_1164.all;

package SMM_noUART_sim_pack is
    procedure SMM_WR_CYCLE(
        WR_ADDR : in std_logic_vector; -- 書き込みアドレスをセットする
        WR_DATA : in std_logic_vector; -- 書きこむデータをセットする
        WR_BE : in std_logic_vector; -- 書きこむBEをセットする
        
        signal clk : in std_logic;
        signal rnw : out std_logic;
        signal cs : out std_logic;
        signal addr : out std_logic_vector;
        signal dout : out std_logic_vector;
        signal be : out std_logic_vector
    );
    
    procedure SMM_RD_CYCLE(
        RD_ADDR : in std_logic_vector; -- 読み出しアドレスをセットする
        RD_BE : in std_logic_vector; -- 読み出し時のBEをセットする
        signal RD_DATA : out std_logic_vector; -- 読み出しデータ
        
        signal clk : in std_logic;
        signal rnw : out std_logic;
        signal cs : out std_logic;
        signal addr : out std_logic_vector;
        din : in std_logic_vector;
        signal be : out std_logic_vector
    );
end SMM_noUART_sim_pack;

package body SMM_noUART_sim_pack is
    procedure SMM_WR_CYCLE(
        WR_ADDR : in std_logic_vector; -- 書き込みアドレスをセットする
        WR_DATA : in std_logic_vector; -- 書きこむデータをセットする
        WR_BE : in std_logic_vector; -- 書きこむBEをセットする
        
        signal clk : in std_logic;
        signal rnw : out std_logic;
        signal cs : out std_logic;
        signal addr : out std_logic_vector;
        signal dout : out std_logic_vector;
        signal be : out std_logic_vector
    ) is
    begin
        wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
        wait for 1 ns; -- 遅延を挟んで
        rnw <= '0'; -- Write
        cs <= '1'; -- enable
        addr <= WR_ADDR;
        dout <= WR_DATA;
        be <= WR_BE;
        
        wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
        wait for 1 ns; -- 遅延を挟んで
        cs <= '0';
    end SMM_WR_CYCLE;
    
    procedure SMM_RD_CYCLE(
        RD_ADDR : in std_logic_vector; -- 読み出しアドレスをセットする
        RD_BE : in std_logic_vector; -- 読み出し時のBEをセットする
        signal RD_DATA : out std_logic_vector; -- 読み出しデータ
        
        signal clk : in std_logic;
        signal rnw : out std_logic;
        signal cs : out std_logic;
        signal addr : out std_logic_vector;
        din : in std_logic_vector;
        signal be : out std_logic_vector
    ) is
    begin
        wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
        wait for 1 ns; -- 遅延を挟んで
        rnw <= '1'; -- Read
        cs <= '1'; -- enable
        addr <= RD_ADDR;
        be <= RD_BE;
        
        wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
        RD_DATA <= din;
        wait for 1 ns; -- 遅延を挟んで
        cs <= '0';
    end SMM_RD_CYCLE;
end SMM_noUART_sim_pack;


次にSMMのシミュレーション・モデルを下に示す。process beginの下のwait for 100 ns;の下に試してみたいスティミュラスを記述する。今回は、タイマーに16をセットして、割り込みがかかるのを待ってから、LCDの命令レジスタにX"34"を書きこむ。次に、South Pushbuttonスイッチの状態をReadする。

-- SMMのシミュレーションモデル
-- IO、Interruptのモデル、シリアル無し

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

library work;
use work.SMM_noUART_sim_pack.all;

entity smm is
    port (
      CLK : in std_logic;
      RESET : in std_logic;
      DIN : in std_logic_vector(0 to 31);
      DOUT : out std_logic_vector(0 to 31);
      BE : out std_logic_vector(0 to 3);
      RNW : out std_logic;
      ADDR : out std_logic_vector(0 to 15);
      CS : out std_logic;
      INTERRUPT : in std_logic;
      INTERRUPT_ACK : out std_logic
    );
end smm;

architecture sim_model of smm is
constant LCD_ADDR : std_logic_vector :=     X"0000";
constant TIMER_ADDR : std_logic_vector :=     X"0010";
constant BUTTON_ADDR : std_logic_vector :=    X"0020";
signal rd_data : std_logic_vector(0 to 31);
type INTERRUPT_STATE is (IDLE_INTR, WAIT_INTR1, WAIT_INTR2, INTR_ACK, WAIT_INTR_LOW);
signal intr_cs : INTERRUPT_STATE;
signal INTERRUPT_ACK_node : std_logic;
begin
    -- 割り込み用ステートマシン
    process(clk, reset) begin
        if reset='1' then
            intr_cs <= IDLE_INTR;
            INTERRUPT_ACK_node <= '0';
        elsif clk'event and clk='1' then
            case intr_cs is
                when IDLE_INTR =>
                    if INTERRUPT='1' then -- 割り込み
                        intr_cs <= WAIT_INTR1;
                    end if;
                when WAIT_INTR1 =>
                    intr_cs <= WAIT_INTR2;
                when WAIT_INTR2 =>
                    intr_cs <= INTR_ACK;
                    INTERRUPT_ACK_node <= '1';
                when INTR_ACK =>
                    intr_cs <= WAIT_INTR_LOW;
                    INTERRUPT_ACK_node <= '0';
                when WAIT_INTR_LOW =>
                    if INTERRUPT='0' then
                        intr_cs <= IDLE_INTR;
                    end if;
            end case;
        end if;
    end process;
    INTERRUPT_ACK <= INTERRUPT_ACK_node after 1 ns;
    
    process begin
        DOUT <= (others => '0');
        BE <= (others => '0');
        ADDR <= (others => '0');
        CS <= '0';
        
        wait for 100 ns;
        
        -- これから下のwaitまでの間にスティミュラスを書く
        
        SMM_WR_CYCLE(TIMER_ADDR, X"00000010", "1111", clk, rnw, cs, addr, dout, be); -- Timerへ書き込み、16クロックカウント
        
        wait until INTERRUPT_ACK_node'event and INTERRUPT_ACK_node='1'; -- INTERRUPT_ACK_node の立ち上がりまでwait
        wait for 1 ns;
        
        SMM_WR_CYCLE(LCD_ADDR, X"12340000", "1111", clk, rnw, cs, addr, dout, be); -- LCDへ書き込み
        
        -- ボタンの状況をrd_dataに読み出し
        SMM_RD_CYCLE(BUTTON_ADDR, "1111", rd_data, clk, rnw, cs, addr, din, be);
        
        wait;
    end process;
end sim_model;


次にテストベンチだが、これはSouth PushbuttonスイッチのButton_Sを1にして、ひたすらwaitするだけだ。

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 lcd_ref_tb IS
END lcd_ref_tb;
 
ARCHITECTURE behavior OF lcd_ref_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT lcd_ref
    PORT(
         Clock : IN  std_logic;
         Reset : IN  std_logic;
         Button_S : IN  std_logic;
         LCD_DB : OUT  std_logic_vector(7 downto 0);
         LCD_RS : OUT  std_logic;
         LCD_RW : OUT  std_logic;
         LCD_E : OUT  std_logic
        );
    END COMPONENT;
    

   --Inputs
   signal Clock : std_logic := '0';
   signal Reset : std_logic := '1';
   signal Button_S : std_logic := '0';

     --Outputs
   signal LCD_DB : std_logic_vector(7 downto 0);
   signal LCD_RS : std_logic;
   signal LCD_RW : std_logic;
   signal LCD_E : std_logic;

   -- Clock period definitions
   constant Clock_period : time := 20 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: lcd_ref PORT MAP (
          Clock => Clock,
          Reset => Reset,
          Button_S => Button_S,
          LCD_DB => LCD_DB,
          LCD_RS => LCD_RS,
          LCD_RW => LCD_RW,
          LCD_E => LCD_E
        );

   -- Clock process definitions
   Clock_process :process
   begin
        Clock <= '0';
        wait for Clock_period/2;
        Clock <= '1';
        wait for Clock_period/2;
   end process;
 

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

      -- insert stimulus here 

      wait;
   end process;

END;


これをISEにシミュレーション専用でプロジェクトに追加すると、ImplementationとSimulationでSMMが切り替わってとても具合が良い。
SMM_31_101202.png
SMM_32_101202.png

これでISimでシミュレーションをした結果を下に示す。
SMM_33_101202.png

最初にcsが1になって0に戻ったところで、タイマーに16をセットして、その間waitして、interrupt_ackが来たら、wait状態から抜けだして、次のcs=1でLCDの命令レジスタにX"34"を書きこむ。その結果として、lcd_dbが34になって、lcd_eが260nsecの間、1になる。その次のcs=1でbutton_sの内容をrd_dataの最上位ビットに読み込む。

これで、SMM周辺回路のシミュレーションでのデバックは出来る状況になったと思う。
  1. 2010年12月02日 04:47 |
  2. SMM
  3. | トラックバック:0
  4. | コメント:0