読者です 読者をやめる 読者になる 読者になる

日曜技術者のメモ

趣味でやった事のメモ書きです。

qemu2svを試してみた-3-

QEMU SystemVerilog

qemu2svを試してみた-2- - 日曜技術者のメモの続き
プログラムを書いてWrite/Readテストをした

qemu⇔svの通信テスト

通信プログラムの作成

qemuからsvへアクセスする為のプログラムを作成した。
sv側にライトしてからリードするだけのプログラム。

  • main.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int main(void){
  int  mem_fd;
  void *hw_if_map;
  volatile unsigned int* phy_pt;
  unsigned int ret;
  int i;
  if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
     printf("can't open /dev/mem \n");
     return 0;
  }  

  hw_if_map = mmap(
      NULL,             //Any adddress in our space will do
      BLOCK_SIZE,       //Map length
      PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
      MAP_SHARED,       //Shared with other processes
      mem_fd,           //File to map
      0xe0004000         //Offset to GPIO peripheral
   );
  close(mem_fd);

  phy_pt = hw_if_map;

  for (i = 0 ;i < 0x100 ; i = i + 4){
    printf("CPU Write Address = 0x%x data = 0x%x\n",0xe0004000+i,i + 0x10 );
    *(phy_pt+i) = (0x10 + i);
    printf("CPU Read Address = 0x%x\n",0xe0004000+i);
    ret = *(phy_pt+i);
    printf("CPU Read Data = 0x%x\n",ret);

    if (ret != (0x10 + i)){
      printf("Error::not compare\n");
      return 0;
    }
  }
  return 1;
}

ビルド

XilinxSDKの中にあるarm-xilinx-linux-gnueabi-gccを使ってビルドした。

/opt/Xilinx/SDK/2014.2/gnu/arm/lin/bin/arm-xilinx-linux-gnueabi-gcc -o ./main main.

QEMU Linuxに転送

QEMU上ではFTPサーバーが動作しているのでFTPを使って送付する。 ビルドしたmainと同じフォルダに以下テキストを作成。

open localhost 10021                                                                                  
user root root                                                                                        
passive                                                                                               
put main                                                                                              
close

作成後ftp -n < ftp.txtを実行する事でQEMU Linuxのルートディレクトリにファイルが送られる。

動作確認。

QEMU Linux上にmainがある事が確認できたらchmod +x mainで実行権限を与えておく。

後はQEMU Linux上で./mainを実行する。

zynq> ./main
CPU Write Address = 0xe0004000 data = 0x10
CPU Read Address = 0xe0004000
CPU Read Data = 0x10
CPU Write Address = 0xe0004004 data = 0x14
CPU Read Address = 0xe0004004
CPU Read Data = 0x14

・・・

CPU Write Address = 0xe00040f8 data = 0x108
CPU Read Address = 0xe00040f8
CPU Read Data = 0x108
CPU Write Address = 0xe00040fc data = 0x10c
CPU Read Address = 0xe00040fc
CPU Read Data = 0x10c
zynq> 
  • sv側
# Start server connect...
# sv::write::rw_packet.offset = 0x00000000 rw_packet.data = 0x00000010
# 
# sv::read::rw_packet.offset = 0x00000000 rw_packet.data = 0x00000010
# 
# sv::write::rw_packet.offset = 0x00000010 rw_packet.data = 0x00000014
# 
# sv::read::rw_packet.offset = 0x00000010 rw_packet.data = 0x00000014
# 
# sv::write::rw_packet.offset = 0x00000020 rw_packet.data = 0x00000018
# 
# sv::read::rw_packet.offset = 0x00000020 rw_packet.data = 0x00000018

・・・

# sv::write::rw_packet.offset = 0x000003e0 rw_packet.data = 0x00000108
# 
# sv::read::rw_packet.offset = 0x000003e0 rw_packet.data = 0x00000108
# 
# sv::write::rw_packet.offset = 0x000003f0 rw_packet.data = 0x0000010c
# 
# sv::read::rw_packet.offset = 0x000003f0 rw_packet.data = 0x0000010c
#

ちゃんとアクセスしている様に見えるがアドレスが違うと思い調べた結果、sv側のoffsetを2ビット右シフトする事でアドレスが一致しました。

QEMUを終了するにはQEMUのターミナル上でCtrl+Aを入力した後xを入力すると終了します。
(その際sv側も勝手に終了する。)

終了する際に気になったのはQEMU側を終了際にsv側にアクセスが発生する様です。 以下終了時のログには0x00000000へ2回リードが発生している。

# sv::read::rw_packet.offset = 0x000003f0 rw_packet.data = 0x0000010c
# 
# sv::read::rw_packet.offset = 0x00000000 rw_packet.data = 0x00000010
# 
# sv::read::rw_packet.offset = 0x00000000 rw_packet.data = 0x00000010
# 
# SV::connection faild
# 
# ** Note: $finish    : mem_model.sv(47)
#    Time: 95 ps  Iteration: 1  Instance: /mem_model
[ginnyu-tei@localhost svdpi_test]$ 

そこそこ簡単にQEMUとSVが通信できました。
後シミュレーション時間が同期できればおもしろいかなー