FC2カウンター FPGAの部屋 ZedBoardにビットマップ・ディスプレイ・コントローラを追加する14(ソースの公開)
FC2ブログ

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

FPGAの部屋

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

ZedBoardにビットマップ・ディスプレイ・コントローラを追加する14(ソースの公開)

ZedBoardにビットマップ・ディスプレイ・コントローラを追加する13(char_wirte_axi_master IPを追加4)”の続き。

ビットマップ・ディスプレイ・コントローラのAXI4 IPのソースは、”ビットマップ・ディスプレイ・コントローラの作製19(HDLソースの公開)”で公開してあって、そこからほとんど修正していない。そこで、ビットマップ・ディスプレイ・コントローラは省略とする。
DDR3 SDRAMのフレーム・バッファにキャラクタを書き込むchar_write_axi_master IPのソースを公開する。
先ずは、char_write_axi_master.vhd から下に示す。char_write_axi_master.vhd は、char_gen_8raster.v が作ったキャラクタのピクセルデータが揃ったら、1ラスタずつ、64ビット幅4バーストでキャラクタのピクセルデータをDDR3 SDRAMに転送する。それを8ラスタ行う。

-------------------------------------------------------------------------------
--
-- AXI Master
--
-- VHDL-Standard:   VHDL'93
----------------------------------------------------------------------------
--
-- Structure:
--   char_write_axi_master
--
----------------------------------------------------------------------------

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

package m_seq_pack is
    function M_SEQ24_F(mseq24in : std_logic_vector
        )return std_logic_vector;
end package m_seq_pack;
package body m_seq_pack is
    function M_SEQ24_F(mseq24in : std_logic_vector
        )return std_logic_vector is
            variable mseq24 : std_logic_vector(23 downto 0);
            variable xor_result : std_logic;
    begin
        xor_result := mseq24in(23) xor mseq24in(3) xor mseq24in(2) xor mseq24in(0);
        mseq24 := mseq24in(22 downto 0) & xor_result;
        return mseq24;
    end M_SEQ24_F;
end m_seq_pack;


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

library work;
use work.m_seq_pack.all;

--library unisim;
--use unisim.vcomponents.all;

entity char_write_axi_master is
  generic(
    C_M_AXI_SUPPORTS_THREADS            : integer := 0;
    C_M_AXI_THREAD_ID_WIDTH             : integer := 1;
    C_M_AXI_ADDR_WIDTH                     : integer := 32;
    C_M_AXI_DATA_WIDTH                     : integer := 64;
    C_INTERCONNECT_M_AXI_WRITE_ISSUING    : integer := 8;
    C_INTERCONNECT_M_AXI_READ_ISSUING    : integer := 8;
    C_M_AXI_SUPPORTS_READ                : integer := 0;
    C_M_AXI_SUPPORTS_WRITE                : integer := 1;
    C_M_AXI_SUPPORTS_USER_SIGNALS        : integer := 0;
    C_M_AXI_AWUSER_WIDTH                : integer := 1;
    C_M_AXI_ARUSER_WIDTH                : integer := 1;
    C_M_AXI_WUSER_WIDTH                 : integer := 1;
    C_M_AXI_RUSER_WIDTH                 : integer := 1;
    C_M_AXI_BUSER_WIDTH                 : integer := 1;
    C_M_AXI_SUPPORTS_NARROW_BURST        : integer := 0;
    C_M_AXI_TARGET                        : std_logic_vector(31 downto 0) := x"00000000";
    C_M_AXI_BURST_LEN                    : integer := 16;
    C_OFFSET_WIDTH                        : integer := 9;
    
    DISP_INTERVAL_DIV                     : integer := 20000000 -- 0.2sec 間隔でキャラクタを書くための分周値
  );
  port(
    -- System Signals
    ACLK    : in std_logic;
    ARESETN : in std_logic;

    -- Master Interface Write Address
    M_AXI_AWID    : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_AWADDR  : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_AWLEN   : out std_logic_vector(8-1 downto 0);
    M_AXI_AWSIZE  : out std_logic_vector(3-1 downto 0);
    M_AXI_AWBURST : out std_logic_vector(2-1 downto 0);
    M_AXI_AWLOCK  : out std_logic;
    M_AXI_AWCACHE : out std_logic_vector(4-1 downto 0);
    M_AXI_AWPROT  : out std_logic_vector(3-1 downto 0);
    -- AXI3    M_AXI_AWREGION:out std_logic_vector(4-1 downto 0);
    M_AXI_AWQOS   : out std_logic_vector(4-1 downto 0);
    M_AXI_AWUSER  : out std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
    M_AXI_AWVALID : out std_logic;
    M_AXI_AWREADY : in  std_logic;

    -- Master Interface Write Data
    -- AXI3   M_AXI_WID(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_WDATA  : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_WSTRB  : out std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
    M_AXI_WLAST  : out std_logic;
    M_AXI_WUSER  : out std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
    M_AXI_WVALID : out std_logic;
    M_AXI_WREADY : in  std_logic;

    -- Master Interface Write Response
    M_AXI_BID    : in  std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_BRESP  : in  std_logic_vector(2-1 downto 0);
    M_AXI_BUSER  : in  std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
    M_AXI_BVALID : in  std_logic;
    M_AXI_BREADY : out std_logic;

    -- Master Interface Read Address
    M_AXI_ARID    : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_ARADDR  : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_ARLEN   : out std_logic_vector(8-1 downto 0);
    M_AXI_ARSIZE  : out std_logic_vector(3-1 downto 0);
    M_AXI_ARBURST : out std_logic_vector(2-1 downto 0);
    M_AXI_ARLOCK  : out std_logic_vector(2-1 downto 0);
    M_AXI_ARCACHE : out std_logic_vector(4-1 downto 0);
    M_AXI_ARPROT  : out std_logic_vector(3-1 downto 0);
    -- AXI3   M_AXI_ARREGION:out std_logic_vector(4-1 downto 0);
    M_AXI_ARQOS   : out std_logic_vector(4-1 downto 0);
    M_AXI_ARUSER  : out std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
    M_AXI_ARVALID : out std_logic;
    M_AXI_ARREADY : in  std_logic;

    -- Master Interface Read Data 
    M_AXI_RID    : in  std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_RDATA  : in  std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_RRESP  : in  std_logic_vector(2-1 downto 0);
    M_AXI_RLAST  : in  std_logic;
    M_AXI_RUSER  : in  std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
    M_AXI_RVALID : in  std_logic;
    M_AXI_RREADY : out std_logic;

    init_done    : in std_logic;
    
    -- Example Design only
    wr_error : out std_logic;
    rd_error : out std_logic
);

end char_write_axi_master;

-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of char_write_axi_master is
constant    RESP_OKAY        : std_logic_vector := "00";
constant    RESP_EXOKAY        : std_logic_vector := "01";
constant    RESP_SLVERR        : std_logic_vector := "10";
constant    RESP_DECERR        : std_logic_vector := "11";

constant    DDR3_START_ADDR    : std_logic_vector := x"10000000";

constant    ROW_ALL_PIXELS : integer := 640;
constant    COULMN_ALL_PIXELS : integer := 480;

constant    SVGA_ADDR_LIMIT : integer := ROW_ALL_PIXELS*COULMN_ALL_PIXELS*4; -- SVGAのアドレスリミット(横ピクセル数 * 縦ピクセル数 * 1ピクセルを表すバイト数)

signal reset_1d, reset_2d, reset : std_logic;
type wr_main_transaction_state is (idle_wr_main, char_bitmap_trans_start, char_bitmap_trans_wait, write_state, wait_state);
signal wr_main_cs, wr_main_1d : wr_main_transaction_state;
type write_transaction_state is (idle_wr, awvalid_assert, data_write_hold, bready_assert, wr_tran_end);
signal wrt_cs : write_transaction_state;
type write_wvalid_state is (idle_wvalid, wvalid_assert, wvalid_hold);
signal wrt_wv_cs : write_wvalid_state;

signal awvalid, wvalid, bready : std_logic;
signal wr_addr, wr_addr_old, wr_addr_sc : std_logic_vector(31 downto 0);
signal awlen, write_count : std_logic_vector(7 downto 0);
signal wlast : std_logic;
signal disp_count : integer;
signal disp_ena : std_logic;
signal wr_tran_count : std_logic_vector(2 downto 0);
signal char_code         : std_logic_vector(6 downto 0);
signal color_code         : std_logic_vector(31 downto 0);
signal char_code_ena     : std_logic;
signal raster_data         : std_logic_vector(63 downto 0);
signal raster_valid        : std_logic;
signal raster_ready        : std_logic;
signal fifo_empty        : std_logic;

component char_gen_8raster
    port(
        clk             : in std_logic;
        reset            : in std_logic;
        char_code        : in std_logic_vector(6 downto 0);
        color_code        : in std_logic_vector(31 downto 0);
        char_code_ena    : in std_logic; -- アスキーキャラクタコードのイネーブル、1パルス
        raster_valid    : out std_logic; -- ラスタデータのRead時のReady信号
        raster_data        : out std_logic_vector(63 downto 0);
        raster_ready    : in std_logic;
        fifo_empty        : out std_logic
    );
end component;

begin
    -- ARESETN をACLK で同期化
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            reset_1d <= not ARESETN or not init_done;
            reset_2d <= reset_1d;
        end if;
    end process;
    reset <= reset_2d;
    
    -- インプリメントでは0.2秒に1回表示する
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                disp_count <= 0;
                disp_ena <= '0';
            else
                if disp_count = DISP_INTERVAL_DIV then
                    disp_count <= 0;
                    disp_ena <= '1';
                else
                    disp_count <= disp_count + 1;
                    disp_ena <= '0';
                end if;
            end if;
        end if;
    end process;
    
    -- Write Transaction State Machine
    -- Writeを0.2秒に1回行う。Readは無し
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_main_cs <= idle_wr_main;
                char_code_ena <= '0';
            else
                case (wr_main_cs) is
                    when idle_wr_main =>
                        wr_main_cs <= char_bitmap_trans_start;
                    when char_bitmap_trans_start => -- キャラクタコードからビットマップデータへの変換をスタート
                        char_code_ena <= '1';
                        wr_main_cs <= char_bitmap_trans_wait;
                    when char_bitmap_trans_wait => -- キャラクタコードからビットマップデータへの変換が終了するまでWait
                        char_code_ena <= '0';
                        if raster_valid='1' then
                            wr_main_cs <= write_state;
                        end if;
                    when write_state =>
                        if wrt_cs = wr_tran_end and wr_tran_count=7 then -- 1キャラクタ描画終了
                            wr_main_cs <= wait_state;
                        end if;
                    when wait_state =>
                        if disp_ena='1' then
                            wr_main_cs <= idle_wr_main;
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    -- writeの数を数える
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_tran_count <= (others => '0');
            else
                if wrt_cs = wr_tran_end then
                    wr_tran_count <= wr_tran_count + 1;
                elsif wr_main_cs = wait_state then
                    wr_tran_count <= (others => '0');
                end if;
            end if;
        end if;
    end process;
    
    -- color_code の処理
    color_code(31 downto 24) <= (others => '0');
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                color_code(23 downto 0) <= (others => '1');
            else
                if wr_main_cs=write_state and wrt_cs = wr_tran_end and wr_tran_count=7 then -- 1キャラクタ描画終了
                    color_code(23 downto 0) <= M_SEQ24_F(color_code(23 downto 0));
                end if;
            end if;
        end if;
    end process;
    -- color_code(23 downto 0) <= (others => '1');

    char_gen_8raster_i : char_gen_8raster port map(
        clk             => ACLK,
        reset            => reset,
        char_code        => char_code,
        color_code        => color_code,
        char_code_ena    => char_code_ena,
        raster_valid    => raster_valid,
        raster_data        => raster_data,
        raster_ready    => raster_ready,
        fifo_empty        => fifo_empty
    );
    
    -- Write
    M_AXI_AWID        <= "0";
    M_AXI_AWSIZE     <= "011";    -- 8 bytes fixed
    M_AXI_AWBURST    <= "01";    -- INCR
    M_AXI_AWLOCK    <= '0';    -- Normal Access
    M_AXI_AWCACHE    <= "0010";    -- Normal Non-cacheable Non-bufferable
    -- M_AXI_AWCACHE    <= "0011";    -- Normal Non-cacheable Bufferable, Zynq-7020ではBRESPが10でSLVERRになってしまい設定してはならない。
    M_AXI_AWPROT    <= "000";    -- Data access, Secure access, Unprivileged access
    M_AXI_AWQOS        <= "0000";    -- default
    M_AXI_AWUSER    <= "0";
    M_AXI_WSTRB        <= (others => '1');
    M_AXI_WUSER        <= "0";
    M_AXI_AWLEN        <= CONV_STD_LOGIC_VECTOR(3, 8); -- 1ライン8ピクセル-1(64ビット幅なので4バースト)
    awlen            <= CONV_STD_LOGIC_VECTOR(3, 8); -- 1ライン8ピクセル-1(64ビット幅なので4バースト)
    
    -- AXI4バス Write Transaction State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wrt_cs <= idle_wr;
                awvalid <= '0';
                bready <= '0';
            else 
                case(wrt_cs) is
                    when idle_wr =>
                        if wr_main_cs = write_state then
                            wrt_cs <= awvalid_assert;
                            awvalid <= '1';
                        end if;
                    when awvalid_assert =>
                        if M_AXI_AWREADY='1' then
                            if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1') then
                                wrt_cs <= bready_assert;
                                bready <= '1';
                            else
                                wrt_cs <= data_write_hold;
                            end if;
                            awvalid <= '0';
                        end if;
                    when data_write_hold =>
                        if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1') then
                            wrt_cs <= bready_assert;
                            bready <= '1';
                        end if;
                    when bready_assert =>
                        if M_AXI_BVALID='1' then
                            wrt_cs <= wr_tran_end;
                            bready <= '0';
                        end if;
                    when wr_tran_end =>
                        wrt_cs <= idle_wr;
                end case;
            end if;
        end if;
    end process;
    -- AXI4 バス Write Transaction WVALID State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wrt_wv_cs <= idle_wvalid;
                wvalid <= '0';
            else 
                case(wrt_wv_cs) is
                    when idle_wvalid =>
                        if wrt_cs=awvalid_assert then
                            wrt_wv_cs <= wvalid_assert;
                            wvalid <= '1';
                        end if;
                    when wvalid_assert =>
                        if write_count=0 and M_AXI_WREADY='1' then -- 終了
                            wrt_wv_cs <= wvalid_hold;
                            wvalid <= '0';
                        end if;
                    when wvalid_hold =>
                        if wrt_cs=bready_assert then
                            wrt_wv_cs <= idle_wvalid;
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    M_AXI_AWVALID    <= awvalid;
    M_AXI_WVALID    <= wvalid;
    M_AXI_BREADY    <= bready;
    
    -- wr_addr の処理、Write Transaction が終了するたびにキャラクタの下のラインをアドレスするために640を足す。
    -- wr_addr_old : キャラクタのベースアドレス(左上)、wr_add_sc : キャラクタの1行の左上のアドレス
    -- 1キャラクタ=4バイと、よってアドレスは*4
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_addr <= DDR3_START_ADDR;
                wr_addr_old <= DDR3_START_ADDR;
                wr_addr_sc <= DDR3_START_ADDR;
            else
                if wrt_cs = wr_tran_end then
                    if wr_tran_count=7 then -- 1キャラクタ描画終了
                        if wr_addr_old >= DDR3_START_ADDR+(SVGA_ADDR_LIMIT-(ROW_ALL_PIXELS*4*8)+(ROW_ALL_PIXELS-8)*4) then -- 1画面描画終了, 640*4*(480-8)+(640-8)*4、1キャラクタは8行なので、総数ピクセルから8行分のピクセルを除いて、最後のキャラクタまでのピクセルを足す
                            wr_addr <= DDR3_START_ADDR;
                            wr_addr_old <= DDR3_START_ADDR;
                            wr_addr_sc <= DDR3_START_ADDR;
                        elsif (wr_addr_sc+(ROW_ALL_PIXELS-8)*4) - wr_addr_old > 0 then -- 次の行に行かない場合
                            wr_addr <= wr_addr_old + 8*4; -- 次のキャラクタのアドレス
                            wr_addr_old <= wr_addr_old + 8*4;
                        else -- 1行キャラクタを書き終わったので、次のキャラクタ行に移動する
                            wr_addr <= wr_addr_sc + ROW_ALL_PIXELS *8 *4; -- x8行 x4バイト
                            wr_addr_old <= wr_addr_sc + ROW_ALL_PIXELS *8 * 4;
                            wr_addr_sc <= wr_addr_sc + ROW_ALL_PIXELS *8 * 4;
                        end if;
                    else -- 同一キャラクタの次の行を描画
                        wr_addr <= wr_addr + ROW_ALL_PIXELS*4;
                    end if;
                end if;
            end if;
        end if;
    end process;
    M_AXI_AWADDR <= wr_addr;
    
    -- write_data の処理、char_gen_8raster のFIFOからデータを出力する
    raster_ready <= '1' when wvalid='1' and M_AXI_WREADY='1' else '0';
    M_AXI_WDATA <= raster_data;
    
    -- write_count の処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                write_count <= (others => '0');
            else
                if wrt_wv_cs=idle_wvalid then
                    write_count <= awlen;
                elsif wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
                    write_count <= write_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- wlastの処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wlast <= '0';
            else
                if wrt_wv_cs=idle_wvalid and awlen=0 then -- awlen が0の時はデータ転送の最初からwlast をアサートする
                    wlast <= '1';
                elsif wrt_wv_cs=wvalid_assert and write_count=1 and M_AXI_WREADY='1' then -- awlen が0で無い時はwrite_count が1でM_AXI_WREADY='1'の時、つまりwrite_count が0の時にwlastをアサートする
                    wlast <= '1';
                elsif wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1' then -- データ転送が終了なのでwlast を0にする
                    wlast <= '0';
                end if;
            end if;
        end if;
    end process;
    M_AXI_WLAST <= wlast;
    
    -- wr_error の処理、M_AXI_BRESPがRESP_OKAY以外の時にwr_errorを点灯する
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_error <= '0';
            else
                if wrt_cs=bready_assert and M_AXI_BVALID='1' and M_AXI_BRESP/=RESP_OKAY then
                    wr_error <= '1';
                end if;
            end if;
        end if;
    end process;
    
    -- char_code の処理
    process(ACLK) begin -- キャラクタコードを+1して表示
        if ACLK'event and ACLK='1' then
            if reset='1' then
                char_code <= "0100001"; -- キャラクタの!
            else
                if wrt_cs = wr_tran_end and wr_tran_count=7 then -- 1キャラクタ描画終了
                    if char_code="1111110" then -- キャラクタの~
                        char_code <= "0100001"; -- キャラクタの!
                    else
                        char_code <= char_code + 1;
                    end if;
                end if;
            end if;
        end if;
    end process;
    
    -- Readは無し
    M_AXI_ARID        <= "0";
    M_AXI_ARLEN        <= (others => '0');
    M_AXI_ARSIZE    <= "010";    -- 4bytes
    M_AXI_ARBURST    <= "01";    -- INCR
    M_AXI_ARLOCK    <= "00";    -- Normal Access
    M_AXI_ARCACHE    <= "0010";    -- Normal Non-cacheable Non-bufferable
    M_AXI_ARPROT    <= "000";    -- Data access, Secure access, Unprivileged access
    M_AXI_ARQOS        <= "0000";    -- default
    M_AXI_ARUSER    <= "0";
    M_AXI_ARADDR    <= (others => '0');
    M_AXI_ARVALID    <= '0';
    M_AXI_RREADY    <= '0';
    rd_error        <= '0';
end implementation;


(2012/10/20、17:23:修正、AXIプロトコル違反になっていたので、修正しました。ご指摘ありがとうございました。)
(2012/10/21:修正、M_AXI_AWCACHE <= "0011"; -- Normal Non-cacheable Bufferable だとM_AXI_BRESPが”01”、SLVERRとなってしまった。BufferableはZynq-7020では使えないようだ。M_AXI_AWCACHE <= "0010"; -- Normal Non-cacheable Non-bufferableに戻した)


次に、char_gen_8raster.v を下に示す。char_gen_8raster.v は、キャラクタROMのビットマップデータを元にピクセルデータを作成してFIFOに入力する。

// キャラクタコードのラスタデータ出力
//
// char_code_ena 1パルスでFIFOにキャラクタコードのラスタデータを読み込む
// すべてのラスタデータを読み込めたら、raster_validが立つ
// 上位モジュールは、ラスタデータを1つ読み終えたら、 raster_ready を立てる
//

`default_nettype none

module char_gen_8raster (
    input    wire    clk,
    input    wire    reset,
    input    wire    [6:0]    char_code,        // アスキーキャラクタコード
    input    wire    [31:0]    color_code,        // カラーコード
    input    wire    char_code_ena,            // アスキーキャラクタコードのイネーブル、1パルス
    output    reg        raster_valid,            // ラスタデータ有効(1パルス)
    output    wire    [63:0]    raster_data,    // ラスタデータ
    input    wire    raster_ready,            // ラスタデータのRead時のReady信号
    output    wire    fifo_empty
);

    parameter [2:0]    IDLE_MAIN =            3'b000,
                    CHAR_ROM_READ =        3'b001,
                    CHAR_ROM_VALID =    3'b011,
                    CONVERT_FORMAT =    3'b010,
                    NEXT_LINE_ST =        3'b110,
                    RASTER_VALID_WAIT =    3'b111,
                    RASTER_VALID_ST =    3'b101;
                    
    reg        [2:0]    mainsm_cs;
    reg        [7:0]    char_shift_reg;
    reg        [6:0]    char_code_hold;
    reg        [31:0]    color_code_hold;
    reg        [2:0]    shift_count;
    reg        [2:0]    row_count;
    reg        [31:0]    bitmap_pixel_data;
    wire    cgfifo_wr_en;
    wire    cgfifo_full;
    wire    cgfifo_underflow;
    wire    [5:0] cgfifo_data_count;
    wire    [7:0]    char_raster_8bit;
    
    // キャラクタ・ジェネレータROMのインスタンス
    char_gen_rom char_gen_rom_inst (
        .clk(clk),
        .reset(reset),
        .char_addr(char_code_hold),
        .row_addr(row_count),
        .dout(char_raster_8bit)
    );
    
    // char_code, color_code をラッチする
    always @(posedge clk) begin
        if (reset) begin
            char_code_hold <= 0;
            color_code_hold <= 0;
        end else begin
            if (mainsm_cs == IDLE_MAIN && char_code_ena) begin
                char_code_hold <= char_code;
                color_code_hold <= color_code;
            end
        end
    end
    
    // main state machine
    always @(posedge clk) begin
        if (reset) begin
            mainsm_cs <= IDLE_MAIN;
            raster_valid <= 1'b0;
        end else begin
            case (mainsm_cs)
                IDLE_MAIN : begin // char_code_ena が1になるとスタート, 0
                    raster_valid <= 1'b0;
                    if (char_code_ena)    // キャラクタのラスタ・ビットマップからRGBビットマップへの変換スタート
                        mainsm_cs <= CHAR_ROM_READ;
                end
                CHAR_ROM_READ : // char_gen_rom のReadのために1クロックWaitする, 1
                    mainsm_cs <= CHAR_ROM_VALID;
                CHAR_ROM_VALID : // この時点で、 char_gen_rom のdoutが確定される, 3
                    mainsm_cs <= CONVERT_FORMAT;
                CONVERT_FORMAT : // キャラクタのラスタ・ビットマップからRGBビットマップへの変換(1ラスタ分), 2
                    if (shift_count == 0) begin
                        if (row_count == 7) // 8ラスタを終了
                            mainsm_cs <= RASTER_VALID_WAIT;
                        else // 次のラスタへ
                            mainsm_cs <= NEXT_LINE_ST;
                    end
                NEXT_LINE_ST : // 次のラスタへの準備, 6
                    mainsm_cs <= CHAR_ROM_READ;
                RASTER_VALID_WAIT : // 1キャラクタ分の変換が終了, char_gen_fifo が32になるまで待機, 7
                    if (cgfifo_data_count >= 32)
                        mainsm_cs <= RASTER_VALID_ST;
                RASTER_VALID_ST : begin // キャラクタがすべてchar_gen_fifo に入ったので、AXIトランザクション開始, 5
                    raster_valid <= 1'b1;
                    mainsm_cs <= IDLE_MAIN;
                end
            endcase
        end
    end                    
    
    // char_gen_rom の出力データ用シフトレジスタ
    always @(posedge clk) begin
        if (reset)
            char_shift_reg <= 0;
        else begin
            if (mainsm_cs == CHAR_ROM_VALID)
                char_shift_reg <= char_raster_8bit[7:0];
            else if (mainsm_cs == CONVERT_FORMAT)
                char_shift_reg <= {1'b0, char_shift_reg[7:1]};
        end
    end
    
    // ピクセルのシフト数のカウント
    always @(posedge clk) begin
        if (reset)
            shift_count <= 3'd7;
        else begin
            if (mainsm_cs == CONVERT_FORMAT && shift_count != 0)
                shift_count <= shift_count - 3'd1;
            else if (mainsm_cs == NEXT_LINE_ST || mainsm_cs == RASTER_VALID_ST)
                shift_count <= 3'd7;
        end
    end
            
    // row_count 
    always @(posedge clk) begin
        if (reset)
            row_count <= 3'd0;
        else begin
            if (mainsm_cs == NEXT_LINE_ST && row_count != 7)
                row_count <= row_count + 3'd1;
            else if (mainsm_cs == IDLE_MAIN)
                row_count <= 3'd0;
        end
    end
    
    // char_gen_fifo へのデータの入力
    always @* begin
        if (char_shift_reg[0])
            bitmap_pixel_data <= color_code_hold;
        else
            bitmap_pixel_data <= 0;
    end
    
    assign cgfifo_wr_en = (mainsm_cs == CONVERT_FORMAT) ? 1'b1 : 1'b0;
    
    // char_gen_fifo のインスタンス
    char_gen_fifo char_gen_fifo_inst (
        .rst(reset), // input rst
        .wr_clk(clk), // input wr_clk
        .rd_clk(clk), // input rd_clk
        .din(bitmap_pixel_data), // input [31 : 0] din
        .wr_en(cgfifo_wr_en), // input wr_en
        .rd_en(raster_ready), // input rd_en
        .dout(raster_data), // output [63 : 0] dout
        .full(cgfifo_full), // output full
        .empty(fifo_empty), // output empty
        .underflow(cgfifo_underflow), // output underflow
        .rd_data_count(cgfifo_data_count) // output [5 : 0] rd_data_count
    );

endmodule                


次に、char_gen_8raster.v で使用しているFIFO、char_gen_fifo のxco ファイルを下に示す。

##############################################################
#
# Xilinx Core Generator version 14.2
# Date: Sat Oct 13 07:46:30 2012
#
##############################################################
#
# This file contains the customisation parameters for a
# Xilinx CORE Generator IP GUI. It is strongly recommended
# that you do not manually alter this file as it may cause
# unexpected and unsupported behavior.
#
##############################################################
#
# Generated from component: xilinx.com:ip:fifo_generator:9.2
#
##############################################################
#
# BEGIN Project Options
SET addpads = false
SET asysymbol = true
SET busformat = BusFormatAngleBracketNotRipped
SET createndf = false
SET designentry = Verilog
SET device = xc7z020
SET devicefamily = zynq
SET flowvendor = Other
SET formalverification = false
SET foundationsym = false
SET implementationfiletype = Ngc
SET package = clg484
SET removerpms = false
SET simulationfiles = Behavioral
SET speedgrade = -1
SET verilogsim = true
SET vhdlsim = false
# END Project Options
# BEGIN Select
SELECT Fifo_Generator xilinx.com:ip:fifo_generator:9.2
# END Select
# BEGIN Parameters
CSET add_ngc_constraint_axi=false
CSET almost_empty_flag=false
CSET almost_full_flag=false
CSET aruser_width=1
CSET awuser_width=1
CSET axi_address_width=32
CSET axi_data_width=64
CSET axi_type=AXI4_Stream
CSET axis_type=FIFO
CSET buser_width=1
CSET clock_enable_type=Slave_Interface_Clock_Enable
CSET clock_type_axi=Common_Clock
CSET component_name=char_gen_fifo
CSET data_count=false
CSET data_count_width=6
CSET disable_timing_violations=false
CSET disable_timing_violations_axi=false
CSET dout_reset_value=0
CSET empty_threshold_assert_value=4
CSET empty_threshold_assert_value_axis=1022
CSET empty_threshold_assert_value_rach=1022
CSET empty_threshold_assert_value_rdch=1022
CSET empty_threshold_assert_value_wach=1022
CSET empty_threshold_assert_value_wdch=1022
CSET empty_threshold_assert_value_wrch=1022
CSET empty_threshold_negate_value=5
CSET enable_aruser=false
CSET enable_awuser=false
CSET enable_buser=false
CSET enable_common_overflow=false
CSET enable_common_underflow=false
CSET enable_data_counts_axis=false
CSET enable_data_counts_rach=false
CSET enable_data_counts_rdch=false
CSET enable_data_counts_wach=false
CSET enable_data_counts_wdch=false
CSET enable_data_counts_wrch=false
CSET enable_ecc=false
CSET enable_ecc_axis=false
CSET enable_ecc_rach=false
CSET enable_ecc_rdch=false
CSET enable_ecc_wach=false
CSET enable_ecc_wdch=false
CSET enable_ecc_wrch=false
CSET enable_read_channel=false
CSET enable_read_pointer_increment_by2=false
CSET enable_reset_synchronization=true
CSET enable_ruser=false
CSET enable_tdata=false
CSET enable_tdest=false
CSET enable_tid=false
CSET enable_tkeep=false
CSET enable_tlast=false
CSET enable_tready=true
CSET enable_tstrobe=false
CSET enable_tuser=false
CSET enable_write_channel=false
CSET enable_wuser=false
CSET fifo_application_type_axis=Data_FIFO
CSET fifo_application_type_rach=Data_FIFO
CSET fifo_application_type_rdch=Data_FIFO
CSET fifo_application_type_wach=Data_FIFO
CSET fifo_application_type_wdch=Data_FIFO
CSET fifo_application_type_wrch=Data_FIFO
CSET fifo_implementation=Independent_Clocks_Block_RAM
CSET fifo_implementation_axis=Common_Clock_Block_RAM
CSET fifo_implementation_rach=Common_Clock_Block_RAM
CSET fifo_implementation_rdch=Common_Clock_Block_RAM
CSET fifo_implementation_wach=Common_Clock_Block_RAM
CSET fifo_implementation_wdch=Common_Clock_Block_RAM
CSET fifo_implementation_wrch=Common_Clock_Block_RAM
CSET full_flags_reset_value=1
CSET full_threshold_assert_value=63
CSET full_threshold_assert_value_axis=1023
CSET full_threshold_assert_value_rach=1023
CSET full_threshold_assert_value_rdch=1023
CSET full_threshold_assert_value_wach=1023
CSET full_threshold_assert_value_wdch=1023
CSET full_threshold_assert_value_wrch=1023
CSET full_threshold_negate_value=62
CSET id_width=4
CSET inject_dbit_error=false
CSET inject_dbit_error_axis=false
CSET inject_dbit_error_rach=false
CSET inject_dbit_error_rdch=false
CSET inject_dbit_error_wach=false
CSET inject_dbit_error_wdch=false
CSET inject_dbit_error_wrch=false
CSET inject_sbit_error=false
CSET inject_sbit_error_axis=false
CSET inject_sbit_error_rach=false
CSET inject_sbit_error_rdch=false
CSET inject_sbit_error_wach=false
CSET inject_sbit_error_wdch=false
CSET inject_sbit_error_wrch=false
CSET input_data_width=32
CSET input_depth=64
CSET input_depth_axis=1024
CSET input_depth_rach=16
CSET input_depth_rdch=1024
CSET input_depth_wach=16
CSET input_depth_wdch=1024
CSET input_depth_wrch=16
CSET interface_type=Native
CSET output_data_width=64
CSET output_depth=32
CSET overflow_flag=false
CSET overflow_flag_axi=false
CSET overflow_sense=Active_High
CSET overflow_sense_axi=Active_High
CSET performance_options=First_Word_Fall_Through
CSET programmable_empty_type=No_Programmable_Empty_Threshold
CSET programmable_empty_type_axis=No_Programmable_Empty_Threshold
CSET programmable_empty_type_rach=No_Programmable_Empty_Threshold
CSET programmable_empty_type_rdch=No_Programmable_Empty_Threshold
CSET programmable_empty_type_wach=No_Programmable_Empty_Threshold
CSET programmable_empty_type_wdch=No_Programmable_Empty_Threshold
CSET programmable_empty_type_wrch=No_Programmable_Empty_Threshold
CSET programmable_full_type=No_Programmable_Full_Threshold
CSET programmable_full_type_axis=No_Programmable_Full_Threshold
CSET programmable_full_type_rach=No_Programmable_Full_Threshold
CSET programmable_full_type_rdch=No_Programmable_Full_Threshold
CSET programmable_full_type_wach=No_Programmable_Full_Threshold
CSET programmable_full_type_wdch=No_Programmable_Full_Threshold
CSET programmable_full_type_wrch=No_Programmable_Full_Threshold
CSET rach_type=FIFO
CSET rdch_type=FIFO
CSET read_clock_frequency=1
CSET read_data_count=true
CSET read_data_count_width=6
CSET register_slice_mode_axis=Fully_Registered
CSET register_slice_mode_rach=Fully_Registered
CSET register_slice_mode_rdch=Fully_Registered
CSET register_slice_mode_wach=Fully_Registered
CSET register_slice_mode_wdch=Fully_Registered
CSET register_slice_mode_wrch=Fully_Registered
CSET reset_pin=true
CSET reset_type=Asynchronous_Reset
CSET ruser_width=1
CSET synchronization_stages=2
CSET synchronization_stages_axi=2
CSET tdata_width=64
CSET tdest_width=4
CSET tid_width=8
CSET tkeep_width=4
CSET tstrb_width=4
CSET tuser_width=4
CSET underflow_flag=true
CSET underflow_flag_axi=false
CSET underflow_sense=Active_High
CSET underflow_sense_axi=Active_High
CSET use_clock_enable=false
CSET use_dout_reset=true
CSET use_embedded_registers=false
CSET use_extra_logic=true
CSET valid_flag=false
CSET valid_sense=Active_High
CSET wach_type=FIFO
CSET wdch_type=FIFO
CSET wrch_type=FIFO
CSET write_acknowledge_flag=false
CSET write_acknowledge_sense=Active_High
CSET write_clock_frequency=1
CSET write_data_count=false
CSET write_data_count_width=7
CSET wuser_width=1
# END Parameters
# BEGIN Extra information
MISC pkg_timestamp=2012-06-23T13:35:37Z
# END Extra information
GENERATE
# CRC: a331f18e


(2012/12/16:追加)char_gen_rom.v を追加で貼っておきます。ダウンロードできるファイルの中にはあったと思うのですが、ソースファイルはブログに貼ったことがないみたいです。
自作のキャラクタROMです。8x8の四角を塗りつぶして作りました。すごい手間が掛かってますよ~。

// キャラクタジェネレータ用ROM

`default_nettype none
`timescale 1ns / 1ps

module char_gen_rom(clk, reset, char_addr, row_addr, dout);
    input clk;
    input reset;
    input [6:0] char_addr;
    input [2:0] row_addr;
    output [7:0] dout;
    
    wire clk;
    wire reset;
    wire [6:0] char_addr;
    wire [2:0] row_addr;
    wire [7:0] dout;
    
    wire [10:0] addr;
    
    assign addr = {1'b0, char_addr, row_addr};
    
    RAMB16_S9 #(
        .INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_08(256'h0014147F147F1414000000000012243600080008080808080000000000000000), // #,",!, 
        .INIT_09(256'h0000000000081018004C322254081408002152240812254200083E483E093E08), // ',&,%,$
        .INIT_0A(256'h000808087F08080800492A1C7F1C2A4900040810101008040020100808081020), // +,*,),(
        .INIT_0B(256'h00010204081020400006060000000000000000007F0000000002040600000000), // /,.,-,,
        .INIT_0C(256'h001C22201820221C003E02041820221C001C080808080C080018244242422418), // 3,2,1,0
        .INIT_0D(256'h001010202040407E003C42423E02423C001E20201E02023E0020207E22242830), // 7,6,5,4
        .INIT_0E(256'h0004080C00000C000000000C00000C00003C42407C42423C003C42423C42423C), // ;,:,9,8
        .INIT_0F(256'h000800081020221C00040810201008040000003E003E00000020100804081020), // ?,>,=,<
        .INIT_10(256'h001C22010101221C003F41413F41413F0041417F2236141C005C2A155549221E), // C,B,A,@
        .INIT_11(256'h001C22710101221C000101013F01017F007F01013F01017F001F21414141211F), // G,F,E,D
        .INIT_12(256'h0022120A060A1222000E11101010103E001C08080808081C004141417F414141), // K,J,I,H
        .INIT_13(256'h001C22414141221C00416151494543410041414149556341003E020202020202),// O,N,M,L
        .INIT_14(256'h003C42403C02423C002111093F41413F005C26594141221C000101013F41413F), // S,R,Q,P
        .INIT_15(256'h00225555554949490008141422224141001C224141414141000808080808087F), // W,V,U,T
        .INIT_16(256'h0038080808080838003F02040810203F00080808081422410041221408142241), // [,Z,Y,X
        .INIT_17(256'h007F0000000000000000000000221408001C10101010101C0008083E083E1422), // _,^,],\
        .INIT_18(256'h0038040438000000001E22221E020200003C223C201C00000000000000180810), // c,b,a,`
        .INIT_19(256'h001C221C0C122C00000808081C081000001C021E221C0000003C22223C202000), // g,f,e,d
        .INIT_1A(256'h0024140C14240400000C1210100010000008080800080000002424241C040400), // k,j,i,h
        .INIT_1B(256'h0018242424180000002828282814000000545454542A00000018080808080800), // o,n,m,l
        .INIT_1C(256'h0018201804180000000404040C34000000202038243800000004041C241C0000), // s,r,q,p
        .INIT_1D(256'h00142A2A2A2200000008141422220000001824242424000000180808081C0800), // w,v,u,t
        .INIT_1E(256'h001008080C080810003E0408103E000000020408142200000022140814220000), // {,z,y,x
        .INIT_1F(256'h0000000000000000000000000000142800040808180808040008080808080808), //  ,~,},|
        .INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
    ) CHAR_GEN_ROM_INST (
        .DO(dout),
        .DOP(),
        .ADDR(addr),
        .CLK(clk),
        .DI(8'd0),
        .DIP(1'b0),
        .EN(1'b1),
        .SSR(reset),
        .WE(1'b0)
    );
endmodule

  1. 2012年10月20日 04:55 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:2

コメント

char_write_axi_master.vは
char_write_axi_master.vhdですよね?

あとchar_gen_rom.vがないとエラーが出たので
を別記事から抜粋させて頂きました。
これでとりあえずビットマップ・ディスプレイ・コントローラ側のnetlistもできました。

ご報告まで
  1. 2012/12/14(金) 15:21:46 |
  2. URL |
  3. tattsuu #-
  4. [ 編集 ]

ありがとうございました。修正しておきました。
char_gen_rom.v も貼っておきました。これは、自分で8x8の四角を塗りつぶして、データにしたキャラクタROMで、すごく大変でした。思い入れがありますね。
  1. 2012/12/16(日) 19:49:43 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

コメントの投稿


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

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