ZynqのPSからのPL制御を考えてみた。
普段、テストベンチレベルではPSからPLへのアクセスは/dev/mem開いて直接制御しちゃいます。
なので、面倒に感じるのかもしれませんが次のよう間にラッパーをかましてしまえば、上位テストアプリは共通化で、SystemVerilogでも安易にアクセスできそうです。
これは一例ってことで・・・
関数名 | 概要 |
---|---|
hw_open | デバイスのオープン |
hw_read | データの読込み |
hw_write | データの書込み |
hw_close | デバイスのクローズ |
fd = hw_open(FILE, address);
PLデバイスをオープンします。 関数内部では次のように処理します。
#if 実機環境
fd = open("/dev/mem", O_RDWR | O_SYNC );
if( fd == -1 ){
return -1;
}
base = mmap(NULL, MAP_LENG, PROT_READ | PROT_WRITE, MAP_SHARED, fd, address & 0xFFFF0000);
if( addr == MAP_FAILED ){
return -1;
}
base_table[fd] = base;
return fd;
#else SystemVerilog環境
base_table[fd] = address;
return fd;
#end
関数内部でbaseを持つってことは、グルーバル配列でテーブルを保持させます。
size = hw_read(fd, address, data, size);
データの読込みではfdに該当するベースアドレスからデータの読込みを行います。
#if 実機環境
base = base_table(fd);
offset = base - address;
for(i=0;i<size;i++){
data[i] = base[i];
}
#else SystemVerilog環境
base = table_base(fd);
for(i=0;i<size;i++){
data[i] = sv_read(base+i);
}
#end
size = hw_write(fd, address, data, size);
データの書込みではfdに該当するベースアドレスにデータを書き込みます。
#if 実機環境
base = base_table(fd);
offset = base - address;
for(i=0;i<size;i++){
base[i] = data[i];
}
#else SystemVerilog環境
base = table_base(fd);
for(i=0;i<size;i++){
sv_write(base+i, data[i]);
}
#end
result = hw_close(fd);
クローズはmmapを開放して、closeします。
#if 実機環境
base = base_table[fd];
munmap(base, MAP_LENG);
close(fd);
#else SystemVerilog環境
table_base[fd]を破棄する
#end
こうしておいて、おけば、上位層は同じままで作れるよね。
SystemVerilogのtaskの動かし方はSystemVerilog側で細工しておくと・・・
でも、まだ試していないので動作するかは不明・・・