FC2カウンター FPGAの部屋 YUV-RGB変換4(シミュレーション)
FC2ブログ

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

FPGAの部屋

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

YUV-RGB変換4(シミュレーション)

YUV-RGB変換3(画像ボードやタイミングの再検討)”の続き。
YUV-RGB回路のコーディングが終了したのでシミュレーションをしてみた。
まずはストラテジーを説明すると、下のタイミングチャートを見るとわかる通りに、SRAMの帯域はYに対してUVは1/2を割り当ててある。つまりSRAMにWriteする部分ではYUV422をそのままWriteする。
YUV_RGB_conv_4_091128.png

よって、モジュールの機能は少し違うが下のブロック図でいうと、VGA_Display_Controller にYUV-RGB変換回路を実装してある。
Camera_Disp_4_090921.png

VGA_Display_Controller がYとUVデータを読み込み、1クロック分保存する。それは、上のたタイミングチャートを見るとわかるが、SRAMにWrite、Readアクセスを交互に行っているからだ。Readは1クロックおきとなるので、16ビット長のReadされたYデータは現在のクロックで上位8ビット、次のクロックで下位8ビットと使用する。UVデータはReadされた16ビット長の上位8ビットにUデータが、下位8ビットにVデータが割り当てられている。UVデータは8ビットだけなので2クロック間同じデータを使用する。
YUV-RGB変換のVHDLコードを下に示す。後で作成する画像処理回路のために掛け算器はできるだけ温存しておくつもりなので、掛け算器を使わずにあえて足し算で記述することにした。

    -- YUV-RGB変換 U=pixel_uv_data(15 downto 8), V=pixel_uv_data(7 downto 0)
    -- R = (Y<<8 + "1_0110_0100"*V - X"B380")>>8
    -- G = (Y<<8 - "1011_0111"*V - "0101_1000"*U + X"8780")>>8
    -- B = (Y<<8 + "1_1100_0110"*U - X"E300")>>8
    y <= pixel_y_data(15 downto 8) when data_enable='1' else pixel_ydata_1d(7 downto 0);
    u <= pixel_uv_data(15 downto 8) when data_enable='1' else pixel_uvdata_1d(15 downto 8);
    v <= pixel_uv_data(7 downto 0) when data_enable='1' else pixel_uvdata_1d(7 downto 0);
    
    conv_r <= ("000" & y & "00000000")        -- Y<<8
                + ("000" & v & "00000000")     -- "1_0000_000"*V
                + ("00000" & v & "000000")    -- "100_0000"*V
                + ("000000" & v & "00000")    -- "10_0000"*V
                + ("000000000" & v & "00")    -- "100"*V
                - ("000" & X"B380"); -- R = (Y<<8 + "1_0110_0100"*V - X"B380")
                
    conv_g <= ("000" & y & "00000000")        -- Y<<8
                - ("0000" & v & "0000000")    -- "1000_0000"*V
                - ("000000" & v & "00000")    --   "10_0000"*V
                - ("0000000" & v & "0000")    --    "1_0000"*V
                - ("000000000" & v & "00")    --       "100"*V
                - ("0000000000" & v & "0")    --        "10"*V
                - ("00000000000" & v)        --             V
                - ("00000" & u & "000000")    --  "100_0000"*U
                - ("0000000" & u & "0000")    --    "1_0000"*U
                - ("00000000" & u & "000") --       "1000"*U
                + ("000" & X"8780"); -- G = (Y<<8 - "1011_0111"*V - "0101_1000"*U + X"8780")
    conv_b <= ("000" & y & "00000000")        -- Y<<8
                + ("000" & u & "00000000")    -- "1_0000_0000"*U
                + ("0000" & u & "0000000")    -- "  1000_0000"*U
                + ("00000" & u & "000000")    -- "   100_0000"*U
                + ("000000000" & u & "00")    -- "        100"*U
                + ("0000000000" & u & "0")    -- "         10"*U
                - ("000" & X"E300"); -- B = (Y<<8 + "1_1100_0110"*U - X"E300")
    
    -- 飽和演算と丸め+右8ビットシフト
    process(conv_r) begin
        if conv_r(18)='1' then -- 値がマイナスの場合
            sat_conv_r <= (others => '0');
        elsif conv_r(17)='1' or conv_r(16)='1' then -- 飽和
            sat_conv_r <= (others => '1');
        else -- 右8ビットシフト
            sat_conv_r <= conv_r(15 downto 8);
        end if;
    end process;
    process(conv_g) begin
        if conv_g(18)='1' then -- 値がマイナスの場合
            sat_conv_g <= (others => '0');
        elsif conv_g(17)='1' or conv_g(16)='1' then -- 飽和
            sat_conv_g <= (others => '1');
        else -- 右8ビットシフト
            sat_conv_g <= conv_g(15 downto 8);
        end if;
    end process;
    process(conv_b) begin
        if conv_b(18)='1' then -- 値がマイナスの場合
            sat_conv_b <= (others => '0');
        elsif conv_b(17)='1' or conv_b(16)='1' then -- 飽和
            sat_conv_b <= (others => '1');
        else -- 右8ビットシフト
            sat_conv_b <= conv_b(15 downto 8);
        end if;
    end process;


19ビットで演算をして、最上位ビットが立っている場合は、マイナスなので0に丸めた。絶対値の方が良いのかどうか分からないが、とりあえず0としてみた。16ビット目と17ビット目が立っている場合はオーバーフローなのでX"FF"に設定した。それ以外の場合は8ビット右シフトを行った。
シミュレーションのwaveウインドウのYUV-RGB変換結果の部分を下に示す。
YUV_RGB_conv_5_091207.png

これは0ラインの最初の部分だが、ピンクの四角で過去った部分はYが55、Uが55、VがAAとなっている。それを右8ビットシフトする前のYUV-RGB演算値がconv_r, conv_b, conv_g である。その値をもとに飽和演算した値が、sat_conv_r, sat_conv_b, sat_conv_g となる。conv_r だけ手計算してみたが値は合っていた。結構面倒で、あまり手計算したくなくなったけど。。。
というわけで、だいたいできたので、今度はインプリメントして確かめてみるが、その前に1つSRAMを増やしたので、UCFを作り直す必要がある。

テーマ:ハードウェア - ジャンル:コンピュータ

  1. 2009年12月07日 05:26 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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