FC2カウンター FPGAの部屋 ZedBoardにビットマップ・ディスプレイ・コントローラを追加する18(再度ACPポートを使用)
fc2ブログ

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

FPGAの部屋

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

ZedBoardにビットマップ・ディスプレイ・コントローラを追加する18(再度ACPポートを使用)

ZedBoardにビットマップ・ディスプレイ・コントローラを追加する17(ARMのソフトからキャラクタを書けた2)”の続き。

またまたツイッターでACPポートの使用方法がTRMに書いてあると教えてもらったで、やってみることにした。
マニュアルは”Zynq-7000 All Programmable SoC テクニカル リファレンス マニュアル UG585 (v1.6.1) 2013 年 9 月 10 日”の96ページに、ACP の要求として、

コヒーレントな ACP 読み出し要求 : ARVALID と一緒に ARUSER[0] = 1 および ARCACHE[1] = 1 が送信された場合、ACP 読み出し要求はコヒーレントです。

コヒーレントな ACP 書き込み要求 : AWVALID と共に AWUSER[0] = 1 および AWCACHE[1] = 1 が送信 された場合、ACP 書き込み要求はコヒーレントです。


ということで、

assign M_AXI_ARCACHE = 4'b0010; // Normal Non-cacheable Non-bufferable
assign M_AXI_ARUSER = 1'b1; // コヒーレントな ACP 読み出し要求


にして、もう一度、”ZedBoardにビットマップ・ディスプレイ・コントローラを追加する8(ACPを使用)”を見ながら、ビットマップ・ディスプレイ・コントローラで使用するAXIバスのポートをACPポートに変更しました。そうすると、やはりキャラクタの表示波形が乱れた。その様子を図1に示す。
(ACPポートはキャッシュのコヒーレンシを維持できるAXIバスのポートだ。キャッシュのコヒーレンシを維持できれば、AXIバス経由でDDR3 SDRAMにReadする時に、キャシュにReadするアドレスの更新されたデータがあれば、AXIバスのReadをWaitさせて、キャッシュからDDR3 SDRAMにcast outし、その後にプロセッサで更新された正しい値をAXIバス経由でDMAできるはずだ。)
ZedBoad_BitMap_DispCnt_101_121103.jpg
図1 ACPポートを使用したキャラクタ表示(C_M_AXI_SUPPORTS_USER_SIGNALSにチェックなし)

もう一度、XPSプロジェクトを見なおしてみると、bitmap_disp_cntrler_axi_master_0 IPコアのプロパティで、C_M_AXI_SUPPORTS_USER_SIGNALSにチェックが入っていなかったので、チェックを入れた。これは、ユーザー信号をサポートするかどうかを決めるチェックだった。チェックを入れると、下の5つのユーザー信号がハイドから回復した。(図2参照)
ZedBoad_BitMap_DispCnt_103_121103.png
図2 bitmap_disp_cntrler_axi_master_0 IPコアのプロパティ

これで、論理合成、インプリメントを行なって、キャラクタを表示させたところ、だいぶましになったのだが、最初の行がおかしくなってしまった。何度、ソフトウェアを実行しても、おかしいパターンは変わるが、最初の行がいつもおかしい。その様子を図3に示す。
ZedBoad_BitMap_DispCnt_102_121103.jpg
図3 ACPポートを使用したキャラクタ表示(C_M_AXI_SUPPORTS_USER_SIGNALSにチェック入り)

実行しているソフトウェアは、キャッシュのフラッシュをコメントアウトしてあるが、このコメントアウトを外してキャッシュをソフトウェアでフラッシュすると、キャラクタがきちんと表示される。図1、図3を表示したソフトウェアを下に示す。

リスト1 キャッシュのフラッシュを全く行わないビットマップ・ディスプレイ・コントローラ用キャラクタ表示ソフトウェア

/* * drawn_disp.c * *  Created on: 2012/09/25 *      Author: Masaaki */

#include "xparameters.h"
#include "xgpio.h"

#define VIDEO_BUFFER_START_ADDRESS    0x10000000

void Xil_DCacheFlush(void);
void Xil_DCacheFlushLine(unsigned int adr);

// char_draw: アドレスとキャラクタコードを受け取ってそのキャラクタを描画する
// addr : 描画するキャラクタのスタートアドレス
// char_code : 描画するキャラクタのコード
// char_color : 描画するキャラクタのカラー、32ビットで表される、0RGBと8ビットずつで表す
// 戻り値:次のキャラクタの描画先頭アドレスを示す。
unsigned int *char_draw(unsigned int *addr, unsigned char char_code, unsigned int char_color){
    int i,j;
    unsigned int char_pattern;
    unsigned int char_code_int;
    unsigned int *cal_char_addr;
    unsigned int *return_addr;

    char_code_int = (unsigned int)(char_code);
    return_addr = addr + 8;
    cal_char_addr = (unsigned int *)(XPAR_CHAR_ROM_AXI_LITE_0_S_AXI_RNG00_BASEADDR+((char_code_int<<3)<<2)); // キャラジェネROMのデータは32ビット幅で下の8ビットだけ有効
    for(i=0; i<8; i++){
        char_pattern = *(volatile unsigned int *)(cal_char_addr); // キャラクタのパターンを読み出し
        for(j=0; j<8; j++){
            if(char_pattern & 0x1// 7ビット目が1の時はドットを描画
                *(volatile unsigned int *)((unsigned int)addr ^ 4) = char_color;
            else
                *(volatile unsigned int *)((unsigned int)addr ^ 4) = 0// 黒を描画
            // Xil_DCacheFlush();    // 1番目の時間計測
            //if (((unsigned int)addr & 0x1f) == 0x1c) // キャッシュラインの終わりで当該キャッシュラインをフラッシュ
                        //Xil_DCacheFlushLine((unsigned int)addr);
            addr++;
            char_pattern >>= 1// キャラクタのパターンを1ビット右シフト
        }
        addr -= 8// 行の最初のアドレスに戻す
        addr += 640// アドレスを1行下にする
        cal_char_addr++;
    }
    // Xil_DCacheFlush();    // 2番目の時間計測

    return return_addr;
}

int main()
{
    static XGpio GPIOInstance_Ptr;
    int xStatus;
    unsigned char char_code;
    unsigned int * ddr2_addr;
    unsigned int coler_code;
    unsigned int char_cnt;
    int i, j;

    // AXI GPIO Initialization
    xStatus = XGpio_Initialize(&GPIOInstance_Ptr,XPAR_AXI_GPIO_0_DEVICE_ID);
    if(XST_SUCCESS != xStatus)
        print("GPIO INIT FAILED\n\r");
    // AXI GPIO Set the Direction(Output setting)
    XGpio_SetDataDirection(&GPIOInstance_Ptr, 10);
    // init_doneに1を出力
    XGpio_DiscreteWrite(&GPIOInstance_Ptr, 11);

    for (ddr2_addr=(unsigned int *)VIDEO_BUFFER_START_ADDRESS; ddr2_addr<(unsigned int *)((unsigned int)VIDEO_BUFFER_START_ADDRESS + (unsigned int)0x12C000); ddr2_addr++){
        *(volatile unsigned int *)((unsigned int)ddr2_addr ^ 4) = 0;
        //if (((unsigned int)ddr2_addr & 0x1f) == 0x1c) // キャッシュラインの終わりで当該キャッシュラインをフラッシュ
            //Xil_DCacheFlushLine((unsigned int)ddr2_addr);
    }
    // Xil_DCacheFlush();

    ddr2_addr = (unsigned int *)VIDEO_BUFFER_START_ADDRESS;
    char_cnt = 0;
    for(j=0; j<8; j++){
        for(i=1; i<8; i++){
            switch(i){
                case 1 :
                    coler_code = 0xff;
                    break;
                case 2 :
                    coler_code = 0xff00;
                    break;
                case 3 :
                    coler_code = 0xffff;
                    break;
                case 4 :
                    coler_code = 0xff0000;
                    break;
                case 5 :
                    coler_code = 0xff00ff;
                    break;
                case 6 :
                    coler_code = 0xffff00;
                    break;
                case 7 :
                    coler_code = 0xffffff;
            }

            for(char_code=0x21; char_code<0x80; char_code++){
                if(char_code >= 0x80// キャラクタコードが上限に達したら、一番下に戻す
                    char_code = 0x21;
                if (char_cnt!=0 && char_cnt%80==0)
                    ddr2_addr = (unsigned int *)((unsigned int)ddr2_addr + 640*4*7); // 1行書き終わったので、下の行に、アドレスは640ドットx1ピクセル4バイトx7行
                ddr2_addr = char_draw(ddr2_addr, char_code, coler_code); // キャラクタを描画
                char_cnt++;
            }
        }
    }

    //Xil_DCacheFlush();    // 3番めの時間計測
    return 0;
}


リスト1で、if行と共に、Xil_DCacheFlushLine((unsigned int)ddr2_addr); をコメントアウトから回復させると、正常にキャラクタが表示された。
ACPポートを使用すると、なんとも微妙な結果になってしまった。

(2013/10/12:追記)
やっとACPポートがおかしい理由がわかりました。

XPSを立ちあげて、Zynqタブの 64b AXI ACP Slave Port をクリックします。
ZedBoad_BitMap_DispCnt_105_131012.png

ダイアログの Accelerator Coherency Port (ACP) Slave AXI Interface の Use slave driven AxUSER values にチェックを入れます。
ZedBoad_BitMap_DispCnt_106_131012.png

これで、キャッシュのフラッシュのないソフトウェアを走らせると、うまくキャラクタが表示できました。これを忘れていたようです。
ZedBoad_BitMap_DispCnt_104_131012.jpg

ツイッターで、Dyrell6502さんに教えていただきました。本当にありがとうございました。長年の課題が解消出来ました。

(もう一度、追記)
その後、Accelerator Coherency Port (ACP) Slave AXI Interface の Use slave driven AxUSER values のチェックを外しても完全に動作しました。PlanAhead14.2からPlanAhead14.6に移行したのが良かったのかもしれません?
ですが、やはりチェックを入れたほうが良いと思うので、入れておきたいと思います。
  1. 2012年11月03日 05:41 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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