DPI-CでBMPファイルリード
ひとまずの目標であるDPI-Cでの画像読み込みです。前回作成したC言語でのBMPファイル読込モジュールを使用して、画像データをVHDLモジュールへ入力することが出来ました。ヘッダファイルを自作したためコンパイル方法が変わるかも、と思いましたが、ModelSimプロジェクト(mpfファイル)があるフォルダにヘッダファイルを格納するだけで認識しました。
テストベンチの流れは以下の通りです。
1. シミュレーション開始直後にBMPファイル読込。
2. 毎クロック画素データをリード。C関数側で画素インデックスを自動で進めるため、テストベンチ側では毎クロック関数を呼ぶだけ。
3. 入力値を2倍して出力するVHDLモジュールに画素データを入力。
以下ソースです。
・hoge_sv.sv
timeunit 1ns; timeprecision 10ps; module hoge_sv(); // C関数をインポート import "DPI-C" function void callReadBMP(); import "DPI-C" function byte getBMPData(); import "DPI-C" function void freeImage(); // 信号宣言 bit clk_i = 1'b0; // クロック bit srst_i = 1'b1; // リセット byte d_i; // 画像データ byte d_o; // 画素値2倍データ // クロック always begin #5ns clk_i = ~clk_i; end // リセット initial begin #100ns; @(posedge clk_i) #1ps srst_i = 1'b0; end // シミュレーション開始直後にBMPファイル読み込み initial begin callReadBMP(); end // C関数を使用して毎クロック画像データを読み込み always @(posedge clk_i) begin if (srst_i) begin d_i = 8'h00; end else begin d_i = getBMPData(); end end // 入力データを2倍して出力(high clip) hoge_vhd u_vhd ( .srst_i(srst_i), //: in std_logic; .clk_i(clk_i), //: in std_logic; .d_i(d_i), //: in std_logic_vector (7 downto 0); .d_o(d_o) //: out std_logic_vector (7 downto 0) ); endmodule
・hoge_c.c
※前回作成したBMPファイル読込ではファイル読込に"fopen_s","fread_s"を使用しました。これらはマイクロソフト独自関数らしく、gccではコンパイル不可。使用可能な"fopen","fread"に置き換えたため再掲します。またBMP.hの内容は変更ありません。前回記事を参考ください。
#include <stdio.h> #include <stdlib.h> #include "BMP.h" BMPINFO bmpInfo; // BMP構造体 int x, y, stride; // 画像インデックス int width, height; // 画像情報 // BMPファイル読込関数呼び出し void callReadBMP() { char path[64] = "LENNA.bmp"; // 読み込み画像 readBMP(path, &bmpInfo); // BMPファイル読み込み x = 0; // x座標インデックス初期化 y = 0; // y座標インデックス初期化 stride = bmpInfo.bitmapInfoHeader.biWidth; // ストライドは8bitなので横幅 width = bmpInfo.bitmapInfoHeader.biWidth; // 画像幅 height = bmpInfo.bitmapInfoHeader.biHeight; // 画像高さ } // 画素値取得 char getBMPData() { char data = bmpInfo.imageData[x + y * stride]; // 画素値取得 // インデックスを進める // 画像左上から右へ進み、一番右まで進んだら次行の左端からといったように進み // 画像右下まで進んだらまた画像左上から開始して、以下ループ if (x == (width - 1)) { x = 0; if (y == (height - 1)) y = 0; else y += 1; } else { x += 1; } return data; } // 画像メモリ領域解放 void freeImage() { free(bmpInfo.imageData); } // BMPファイル読み込み int readBMP(char* path, BMPINFO* bmpInfo) { FILE *fp; // BMPファイルオープン&存在確認 if ((fp = fopen(path, "rb")) == NULL) { printf("error!!\n"); return -1; } // BITMAPFILEHEADER/bfType読み込み fread(&bmpInfo->bitmapFileHeader.bfType, sizeof(unsigned short), 1, fp); // BMPであることを確認 if (bmpInfo->bitmapFileHeader.bfType != 0x4d42) return -2; // その他情報を読み込む fread(&bmpInfo->bitmapFileHeader.bfSize, sizeof(unsigned long), 1, fp); // bfSize fread(&bmpInfo->bitmapFileHeader.bfReserved1, sizeof(unsigned short), 1, fp); // bfReserved1 fread(&bmpInfo->bitmapFileHeader.bfReserved2, sizeof(unsigned short), 1, fp); // bfReserved2 fread(&bmpInfo->bitmapFileHeader.bfOffBits, sizeof(unsigned long), 1, fp); // bfOffBits // BITMAPINFOHEADER読み込み fread(&bmpInfo->bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp); // BMPINFOHEADERの種類を確認 if (bmpInfo->bitmapInfoHeader.biSize != 40) return -3; // カラーテーブル取得 fread(&bmpInfo->rgbQuad, sizeof(RGBQUAD), 256, fp); // 画像データ格納用領域確保 bmpInfo->imageData = (unsigned char*)malloc(sizeof(unsigned char) * bmpInfo->bitmapInfoHeader.biWidth * bmpInfo->bitmapInfoHeader.biHeight); // 画像データ取得 fread(bmpInfo->imageData, sizeof(char), bmpInfo->bitmapInfoHeader.biWidth * bmpInfo->bitmapInfoHeader.biHeight, fp); fclose(fp); return 0; }
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity hoge_vhd is port ( srst_i : in std_logic; clk_i : in std_logic; d_i : in std_logic_vector (7 downto 0); d_o : out std_logic_vector (7 downto 0) ); end hoge_vhd; architecture rtl of hoge_vhd is signal add : std_logic_vector (8 downto 0); begin -- 加算 add <= ('0' & d_i) + ('0' & d_i); -- high clipして出力 process (clk_i) begin if (rising_edge(clk_i)) then if (srst_i = '1') then d_o <= (others => '0'); else if (add(8) = '1') then d_o <= x"ff"; else d_o <= add(7 downto 0); end if; end if; end if; end process; end rtl;
以下シミュレーション波形です。VHDLモジュールの入力データとして画像データっぽいものが入力され、2倍して出力しています。
恐らく出来ているとは思うのですが、これを検証に使用するにはC関数側でコンペアを行いたいところです。次回のネタにしようと思います。