プログラムの作成 (LIFEゲーム)


今回はプログラムの一例としてライフゲームを取り上げます。
ライフゲームとは以下のような生物シミュレーションです。
今回作成したVGAコントローラはキャラクタタイプの表示装置ですので、表示 したい箇所のビデオメモリに表示したい文字のキャラクタコードを書き込めばOKで す。
VGAのビデオメモリの先頭アドレスはハードウェア設計において "0x85000000" に設定しました。これを "VRAM_BASEADDR" とするとき、書き込みたい箇所の座標をX、 Yとすると、
VRAM_BASEADDR + ( ( Y * 80 ) + X ) * 4 
のアドレスに書き込みます。


プログラミング言語CによるLIFEゲームプログラムは以下のようになります。


ソース コメント
#define VRAM_BASEADDR	0x85000000

#define XSIZ 60
#define YSIZ 20

char what( int , int );
void v_puts( int , int , char * );

static char data1[XSIZ][YSIZ] = {
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
  { 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
};

static char data2[XSIZ][YSIZ];

int
main()
{

  int  i,j,num;
  static char *banner = "Microblaze Softcore Processor Video System";

  v_puts( 0, 0, banner );

  for( j=0; j<16; j++ ){
    for( i=0; i<16 ; i++ ) {
      *( (char *)VRAM_BASEADDR + ((j+9)*80 + (i+64)) * 4 ) = 16*j+i;
    }
  }


  for( i=0; i<XSIZ; i++ ){
    for( j=0 ; j<YSIZ ; j++ ) {
      data2[i][j] = 0;
    }
  }

  while(1) {
    for( i=0; i<XSIZ; i++ ){
      for( j=0 ; j<YSIZ ; j++ ) {
        num=0;
        if( what(i-1,j-1) ) num++;
        if( what(i-1,j  ) ) num++;
        if( what(i-1,j+1) ) num++;
        if( what(i  ,j-1) ) num++;
        if( what(i  ,j+1) ) num++;
        if( what(i+1,j-1) ) num++;
        if( what(i+1,j  ) ) num++;
        if( what(i+1,j+1) ) num++;
        if( what(i,j) ) {
          if( num == 2 || num == 3 )
            data2[i][j]=1;
          else
            data2[i][j]=0;
        } else if( num == 3 ) data2[i][j]=1;
      }
    }

    for( i=0; i<XSIZ; i++ ){
      for( j=0 ; j<YSIZ ; j++ ) {
        data1[i][j] = data2[i][j];
        *( (char *)VRAM_BASEADDR + 1600 + (80*j+(XSIZ-i-1))*4 )
             = data2[i][j] ? '@' : ' ';
        data2[i][j] = 0;
      }
    }

    for( i=0; i<256; i++ ){
      for( j=0 ; j<4000 ; j++ ) {
        *( (char *)VRAM_BASEADDR + 319 ) = i;
      }
    }

  }
}

char what( int i, int j)
{
  if( i < 0 ) return 0;
  if( j < 0 ) return 0;
  if( i == XSIZ ) return 0;
  if( j == YSIZ ) return 0;
  return data1[i][j];
}

void v_puts( int x, int y, char *str )
{
  char *p, *addr;

  addr = (char *)VRAM_BASEADDR + (y*80 + x) * 4;
  for( p=str ; *p!='\0' ; p++, addr+=4 ) {
    *addr = *p;
  }
}







data1[XSIZ][YSIZ] : 生物の初期データ
生物が居るところを 1, 居ない所を 0 としている。
初期データとして、ペンタデカスロン (pentadecathlon) および
グライダーガン (gliderguns) が配置されてある。




























































タイトル文字領域以外の画面の消去





data2 配列の初期化







data1 配列の各要素毎に、周りの8マスの生物の状態を調べて生物の個数をカウ ントする。
中心に生物がいるとき、まわりに2〜3つの生物が居れば、中心 の生物は生き残る。
中心に生物がいないとき、まわりに3つの生物が居れ ば、中心に生物が誕生する。 次世代の状態を data2 配列に作成する。















data2 配列内を data1 配列にコピーするとともに、
画面上に生物の状態を配置する。







256×4000回の時間待ちループ。右上にキャラクタを表示しながらループする。







what( i, j ) : data1 配列内の data1[i][j] の生物の状態を返す関数







v_puts( x, y, string ) : (x,y)座標から string 文字列を画面に表示する。

このプログラムを,ソフトウェアプロジェクトとして作成します。

Microbladeのプログラムは SDK というソフトウェア開発ツールを使用します。 "Project" タブの "Export Hardware Design to SDK..." を実行します。 新しく "Export to SDK/ Launch SDK" ウィンドウが表示されたら "Export & Launch SDK" を押します。

"Workspace Launcher" が起動するので、"Workspace" ディレクトリを適宜設 定してOKを押します。



以下のような、SDKウィンドウが起動します。



次に、ソフトウェアプロジェクトを作成します。"Project Explorer"タブ内で、 マウスの右ボタンを押し、"New"->"C Project" を選択します。
"C Project" ウィンドウが起動するので、
Project name: life
Project type: Executable, Empty Project
Toolchains: Xilinx MicroBlaze GNU Toolchain
を選択して "Finish" を押します。



"Project Explorer"タブ内に"life" が追加されてあるはずです。下図のように "life" の所でマウスの右をクリックし、"New"->"Source File" をマウスの左で選択します。



"New Source File" ウィンドウの "Source file:" の所に "life.c" と入力して "Finish" を押します。



"Project Explorer"タブの隣に、新しく"life.c" タブが現れ、雛形コメント が表示されます。 ここに上に記載のプログラムを入力し、保存します。



次に、入力したプログラムをコンパイルして、プロセッサが理解できる形式の ファイルに変換します。"Project" メニューの "Build All" を選択します。 コンパイル終了後、下記のように "Console" タブに表示されると"life.elf" ファイルが生成されています。
**** Build of configuration Debug for project life ****

make all 
Building file: ../life.c
Invoking: MicroBlaze gcc compiler
mb-gcc -Wall -O0 -g3 -c -fmessage-length=0 -mxl-soft-mul -MMD -MP
-MF"life.d" -MT"life.d" -o"life.o" "../life.c"
Finished building: ../life.c
 
Building target: life.elf
Invoking: MicroBlaze gcc linker
mb-gcc -mxl-soft-mul -o"life.elf"  ./life.o   
Finished building target: life.elf
 
Invoking: MicroBlaze Print Size
mb-size life.elf  |tee "life.elf.size"
   text	   data	      bss	    dec	    hex	filename
   3106	      1488       1056	       5650    1612	life.elf
Finished building: life.elf.size
Done!

それでは実際に、 動作確認 を行ってみます。
| Back | Top | Next |