QA@IT

__raw_writel発行でHangUp

36318 PV

PetaLinux v2015.2.1というやや特殊なOSがArm9_cotex7で動作しています。

process側でioctl(fd, cmd, arg);を発行、Kernel側でmy_ioctl(fd, cmd, arg);で待ち受け、cmd, argを受け取ります。
次にこれをHardに出力します。
_raw_write(arg, linuxAddr);
これによりHard側のLEDが点灯、意図通りに動作した感じです。しかしこの後全くのHangUp状態になりました。
Text, Heap, Stackなどシステム領域を壊したのではないかと疑っています。
FPGAで構成されるHardはBASEADDRESS=0x43c00000への出力を要求しています。これに対応してあらかじめ
linuxAddr = (u32 *)ioremap
nocache(BASEADDRESS, sizeof(unsigned long));
により=0x80958000を取得しています。

_raw_writeそのものの欠陥も考えられます。定義を調べたところ
Linux/arch/arm/include/asm/io.h中で下記のごとく定義されています:
#define __raw_writel __raw_writel
static inline void __raw_writel(u32 val, volatile void __iomem addr)
{
asm volatile("str %1, %0"
: : "Qo" (
(volatile u32 _
force *)addr), "r" (val));
}
ごく単純な内容のもののようです。そこで
*linuxAddr = arg;
で置き換えてみました。結果は同じです。

cat /proc/879/mapsでMemory Mapを調べてみました。879は一例です:

00008000-000a1000 r-xp 00000000 00:02 227 /bin/busybox.nosuid
000a9000-000aa000 rw-p 00099000 00:02 227 /bin/busybox.nosuid
000aa000-000cd000 rw-p 00000000 00:00 0 [heap]
36d13000-36d26000 r-xp 00000000 00:02 357 /lib/libnsl-2.20.so
36d26000-36d2d000 ---p 00013000 00:02 357 /lib/libnsl-2.20.so
36d2d000-36d2e000 r--p 00012000 00:02 357 /lib/libnsl-2.20.so
36d2e000-36d2f000 rw-p 00013000 00:02 357 /lib/libnsl-2.20.so
36d2f000-36d31000 rw-p 00000000 00:00 0
36d31000-36d39000 r-xp 00000000 00:02 358 /lib/libnss_compat-2.20.so
36d39000-36d40000 ---p 00008000 00:02 358 /lib/libnss_compat-2.20.so
36d40000-36d41000 r--p 00007000 00:02 358 /lib/libnss_compat-2.20.so
36d41000-36d42000 rw-p 00008000 00:02 358 /lib/libnss_compat-2.20.so
36d42000-36e6b000 r-xp 00000000 00:02 352 /lib/libc-2.20.so
36e6b000-36e72000 ---p 00129000 00:02 352 /lib/libc-2.20.so
36e72000-36e74000 r--p 00128000 00:02 352 /lib/libc-2.20.so
36e74000-36e75000 rw-p 0012a000 00:02 352 /lib/libc-2.20.so
36e75000-36e78000 rw-p 00000000 00:00 0
36e78000-36ee6000 r-xp 00000000 00:02 356 /lib/libm-2.20.so
36ee6000-36eed000 ---p 0006e000 00:02 356 /lib/libm-2.20.so
36eed000-36eee000 r--p 0006d000 00:02 356 /lib/libm-2.20.so
36eee000-36eef000 rw-p 0006e000 00:02 356 /lib/libm-2.20.so
36eef000-36f0f000 r-xp 00000000 00:02 349 /lib/ld-2.20.so
36f13000-36f16000 rw-p 00000000 00:00 0
36f16000-36f17000 r--p 0001f000 00:02 349 /lib/ld-2.20.so
36f17000-36f18000 rw-p 00020000 00:02 349 /lib/ld-2.20.so
3edec000-3ee0d000 rw-p 00000000 00:00 0 [stack]
3ee9e000-3ee9f000 r-xp 00000000 00:00 0 [sigpage]
ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]

これでみると0x80958000付近が使われているようにも見えません。

Hardが要求する固定のAddressにLinuxが対応できるとは限りません。
ひとつ考えられるのはLinuxが出力しうる領域に対応したMirror RegisterをFPGAで構成されるHardに設け転写するというものです。

Linux側だけでで対処可能な方法、あるいは判断の誤りを指摘していただければ幸いです。

#cat /proc/meminfoを挙げておきます:

MemTotal: 1032580 kB
MemFree: 1014832 kB
MemAvailable: 1010076 kB
Buffers: 0 kB
Cached: 9864 kB
SwapCached: 0 kB
Active: 4064 kB
Inactive: 6176 kB
Active(anon): 4064 kB
Inactive(anon): 6176 kB
Active(file): 0 kB
Inactive(file): 0 kB
Unevictable: 0 kB
Mlocked: 0 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 1032580 kB
LowFree: 1014832 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 376 kB
Mapped: 2440 kB
Shmem: 9864 kB
Slab: 3900 kB
SReclaimable: 1136 kB
SUnreclaim: 2764 kB
KernelStack: 320 kB
PageTables: 80 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 516288 kB
Committed_AS: 11352 kB
VmallocTotal: 2072576 kB
VmallocUsed: 2856 kB
VmallocChunk: 1825488 kB
CmaTotal: 16384 kB
CmaFree: 16112 kB

回答

質問文からの引用

FPGAで構成されるHardはBASEADDRESS=0x43c00000への出力を要求しています。これに対応してあらかじめ

linuxAddr = (u32 *)ioremap_nocache(BASEADDRESS, sizeof(unsigned long));

により=0x80958000を取得しています。

物理アドレスが0x43c00000で、仮想アドレスが0x80958000になっているようですので、仮想アドレスにwriteすればよさそうです(メモリマップドI/O)。なぜwriteアクセス時にハングアップするのかは、私もわかりません...

質問文からの引用

cat /proc/879/mapsでMemory Mapを調べてみました。879は一例です:
...
これでみると0x80958000付近が使われているようにも見えません。

このマップはユーザ空間のプロセスのものですので、見るなら/proc/iomemの方じゃないかと思います。ただし/proc/iomemに表示されるには、ドライバ側でioremapの前にrequest_mem_region()を呼んでI/Oメモリ領域を予約しておく必要があると思います。

参考
http://stackoverflow.com/questions/18580469/content-of-proc-iomem

例えばドライバ初期化時にrequest_mem_region()を呼んで、終了時にrelease_mem_region()を呼べばいいいのかな。あとwriteする前にioremap_nocache()等を呼び、writeした後にiounmap()を呼べばいいのかなと思います。

質問文からの引用

_raw_writeそのものの欠陥も考えられます。定義を調べたところ...

関係あるかどうかわかりませんが、I/Oに__raw_writel()を使っているのはなぜだろう?と思いました。よく見るのはiowrite32()だと思いますが、単純にそれを使ってはいけないのだろうか?と思いました。__raw_writel()は最も低レベル用のような気がしますが、あえて低レベルのものを使う理由が気になっただけで、特に深い理由はありませんが、何となく気になったというレベルの話です。

この辺はハングアップとはあまり関係なさそうな気もします...

また細かい話になりますが、arch/arm/include/asm/io.hを見ると、__raw_xxx()系の上位に当たるものとして、3種類のものが定義されていますね。念のため__raw_writel()に対応するものを抜き出してみます。

(1)IO port access primitives(IOポートという呼称はたぶん便宜的・実際はメモリマップドI/Oのはず)
arch/arm/include/asm/io.h

#define outl(v,p)   ({ __iowmb(); __raw_writel((__force __u32) \
                    cpu_to_le32(v),__io(p)); })

__iowmb()でメモリバリア対応。cpu_to_le32()でプロセッサネイティブなフォーマットからリトルエンディアンに変換。__ioはコメントによると

The machine specific io.h include defines __io to translate an "IO"
address to a memory address.

(2)Memory access primitives
arch/arm/include/asm/io.h

#define writel_relaxed(v,c) __raw_writel((__force u32) cpu_to_le32(v),c)
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })

__iowmb()でメモリバリア対応。cpu_to_le32()でプロセッサネイティブなフォーマットからリトルエンディアンに変換。引数のcはコメントによると

These perform PCI memory accesses via an ioremap region. They don't
take an address as such, but a cookie.

(3)io{read,write}{16,32}be() macros
arch/arm/include/asm/io.h

#define iowrite32be(v,p)    ({ __iowmb(); __raw_writel((__force __u32)cpu_to_be32(v), p); })

__iowmb()でメモリバリア対応。cpu_to_be32()でプロセッサネイティブなフォーマットからビッグエンディアンに変換。

__raw_writel()について
逆にいうと__raw_writel()はメモリバリア対応なしで、プロセッサネイティブなフォーマットでそのままwriteアクセスする、ということになると思います。それで良ければ問題なさそうな気がします。

質問文からの引用

Hardが要求する固定のAddressにLinuxが対応できるとは限りません。
ひとつ考えられるのはLinuxが出力しうる領域に対応したMirror RegisterをFPGAで構成されるHardに設け転写するというものです。

この質問の意味はよく理解できていませんが、gammodlerさんがやっているように固定の(物理)アドレスをプログラムにハードコードし、ioremap()等で仮想アドレスにマップすれば、FPGA側のレジスタにアクセスできるはずと思います。

あと私は詳しくないですが、デバイス毎の差を吸収するにはDevice Treeを使う方法があるんじゃないかと思います。ただしこれは違う話になってしまいますが、参考になりそうなチュートリアルがあったのでURLを挙げておきます。

参考
http://xillybus.com/tutorials/device-tree-zynq-4

編集 履歴 (0)

blunder3様
もうどなたからも回答いただけないものとあきらめかけておりました。本当に感謝いたしております。

XilinxおよびPetalinux環境で参考事例をさがし、iowrite32()の方がBetterに思えたのでこれに変更しております。
以前のPlatformはOS:Debian、 CPU:PowerPCでしたがそれで問題なかったので惰性でそのまま使用しておりました。PowePCはBigEndian、ARMはLittleEndian、しかしこれは影響しないと思います。

iowrite32()でもHangUpの状況は変わりませんが、比較的単純なこのモジュールで無限ループにトラップされることはありうるのか検討してみました。

http://billauer.co.il/blog/2014/08/wmb-rmb-mmiomb-effects/
からの引用:

void iowrite32(u32 val, void __iomem *addr)
{
IO_COND(addr, outl(val,port), writel(val, addr));
}

where IO_COND is previously defined in the same file as follows (the comment is in the sources):
/*

  • Ugly macros are a way of life. */ #define IO_COND(addr, is_pio, is_mmio) do { \ unsigned long port = (unsigned long _force)addr; \ if (port >= PIO_RESERVED) { \ is_mmio; \ } else if (port > PIO_OFFSET) { \ port &= PIOMASK; \ is_pio; \ } else \ bad_io_access(port, #is_pio ); \ } while (0)

bad_io_access(port, #is_pio );の条件になると無限Loopはありうるようにも見えます。
しかし
BASEADDRESS=43c00000
はHard側の開発ツールであるVivadoが割り当てたもので妥当性を欠くとは考えにくいです。
関係筋に問い合わせて結果を報告いたします。
ご意見があればお聞かせください。

編集 履歴 (0)

原因はHardにあることは間違いないと判断、AXIバスの基本をもう一度見直しました。

回答からの引用:
(私の理解では)AXIインターコネクトを通じてPS (Processing System)とPL (Programmable Logic)がやり取りをするさいに、

Billauer
データの読み出し時: PSからPLにデータアドレスを送ると、PLから読み出されたデータとRVALIDが返ってくる。
データの書き込み時: PSからPLにデータアドレスと書き込みデータを送ると、PLからBVALIDが返ってくる。
しかしPLがRVALIDやBVALIDを返さず、無応答だと、PSはハングアップする。
となるので、(もし私の勘違いでなければ)ハングアップの件はPL側の問題の可能性もあるのではないかと思います。
Instructables
がヒントになりました。myIPはXilinxのinterconnectというAXI専用のIPに接続されていますが、Documentsを読んだ範囲ではHand Shakeの仕様が明確に把握できていませんでした。それに代わりこの部分に関する基本モジュールが自動生成されるようになっております。
しかしaccessできるRegister数で改善希望があるのと組み込むprocessが複雑でBuildが不成功に終わったなどの理由で別の方法に走ってしまいました。
これが混乱のもとでした。初心者はやはり基本に忠実であるべきでした。
基本モジュールを何とかInstallしてOUT/INPとも成功しました。
تست روانشناسیAXIはIntel系、PowerPCなどと比較、かなりHardのケアが必要です。それも今回認識しました。今回の質問は結果的にHardが原因でしたがblunder3様の懇切なResにより解決に至りました。これで3回お世話になったことになります。本当にありがとうございました。今後もよろしくお願いいたします。

編集 履歴 (0)

blunder3様
原因はHardにあることは間違いないと判断、AXIバスの基本をもう一度見直しました。

回答からの引用:
(私の理解では)AXIインターコネクトを通じてPS (Processing System)とPL (Programmable Logic)がやり取りをするさいに、

データの読み出し時: PSからPLにデータアドレスを送ると、PLから読み出されたデータとRVALIDが返ってくる。
データの書き込み時: PSからPLにデータアドレスと書き込みデータを送ると、PLからBVALIDが返ってくる。
しかしPLがRVALIDやBVALIDを返さず、無応答だと、PSはハングアップする。
となるので、(もし私の勘違いでなければ)ハングアップの件はPL側の問題の可能性もあるのではないかと思います。

がヒントになりました。myIPはXilinxのinterconnectというAXI専用のIPに接続されていますが、Documentsを読んだ範囲ではHand Shakeの仕様が明確に把握できていませんでした。それに代わりこの部分に関する基本モジュールが自動生成されるようになっております。
しかしaccessできるRegister数で改善希望があるのと組み込むprocessが複雑でBuildが不成功に終わったなどの理由で別の方法に走ってしまいました。
これが混乱のもとでした。初心者はやはり基本に忠実であるべきでした。
基本モジュールを何とかInstallしてOUT/INPとも成功しました。

AXIはIntel系、PowerPCなどと比較、かなりHardのケアが必要です。それも今回認識しました。

今回の質問は結果的にHardが原因でしたがblunder3様の懇切なResにより解決に至りました。

これで3回お世話になったことになります。本当にありがとうございました。今後もよろしくお願いいたします。

編集 履歴 (0)

blunder3様
再三のコメントありがとうございます。

私はPL側の可能性に直行してしまいましたが、今回検索していただいたコメントではドライバー側の問題を指摘しています。主にはアクセスするアドレスを問題視しているようです。
それからメモリアクセスが全く不成功に終わっているような印象を受けましが部分的な成功はあるらしい、ということは最初の1回は成功することが多い私のケースもこれに該当する可能性もあると思いました。
そこでPL側を検討する前にドライバ、主には初期化部分を見直してみようと思います。Xilinxは初期化のためのTemplateを開示してくれています。
従来PowerPCのケースでの成功例があるのでそれで良しとして必ずしもTemplateに従っていません。
Templateにある以下を全く実行していません:

static int mydev_probe(struct platform_device pdev)
{
struct resource *r_irq; /
Interrupt resources /
struct resource *r_mem; /
IO mem resources */
struct device *dev = &pdev->dev;
struct mydev_local *lp = NULL;

int rc = 0;

dev_info(dev, "Device Tree Probing\n");

/* Get iospace for the device */
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r_mem) {
    dev_err(dev, "invalid address\n");
    return -ENODEV;
}

lp = (struct mydev_local *) kmalloc(sizeof(struct mydev_local), GFP_KERNEL);
if (!lp) {
    dev_err(dev, "Cound not allocate mydev device\n");
    return -ENOMEM;
}

dev_set_drvdata(dev, lp);

lp->mem_start = r_mem->start;
lp->mem_end = r_mem->end;

if (!request_mem_region(lp->mem_start,
            lp->mem_end - lp->mem_start + 1,
            DRIVER_NAME)) {
    dev_err(dev, "Couldn't lock memory region at %p\n",
        (void *)lp->mem_start);
    rc = -EBUSY;
    goto error1;
}

lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
if (!lp->base_addr) {
    dev_err(dev, "mydev: Could not allocate iomem\n");
    rc = -EIO;
    goto error2;
}

/* Get IRQ for the device */
r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!r_irq) {
    dev_info(dev, "no IRQ found\n");
    dev_info(dev, "mydev at 0x%08x mapped to 0x%08x\n",
        (unsigned int __force)lp->mem_start,
        (unsigned int __force)lp->base_addr);
    return 0;
}
lp->irq = r_irq->start;

rc = request_irq(lp->irq, &mydev_irq, 0, DRIVER_NAME, lp);
if (rc) {
    dev_err(dev, "testmodule: Could not allocate interrupt %d.\n",
        lp->irq);
    goto error3;
}

dev_info(dev,"mydev at 0x%08x mapped to 0x%08x, irq=%d\n",
    (unsigned int __force)lp->mem_start,
    (unsigned int __force)lp->base_addr,
    lp->irq);
return 0;

error3:
free_irq(lp->irq, lp);
error2:
release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
error1:
kfree(lp);
dev_set_drvdata(dev, NULL);
return rc;
}

mydev_probeはここで登録されているようです。

static struct platform_driver mydev_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = mydev_of_match,
},
.probe = mydev_probe,
.remove = mydev_remove,
};

fileoperationのケースでは登録されたものをProcess側でDevice file openを実行することでsystem callが有効になるようにmydev_probeのトリガーもprocess側からかけるものなのかもしれません。この辺りが分かりません。まあ、static int __init mydev_init(void)
のなかで呼んでしまえば済むことではあると思いますが。
結果については報告いたします。
今後もご支援いただければ幸いです。

編集 履歴 (0)

writeするとハングアップする件ですが、たしかにハード側に起因するかもしれないです。XILINKのフォーラムで同じような問題が取り上げられているようです。

Zynq Linux Freeze on Memory Mapped Peripheral Write
https://forums.xilinx.com/t5/Embedded-Linux/Zynq-Linux-Freeze-on-Memory-Mapped-Peripheral-Write/td-p/246156

追記

私はこの話題に詳しくないので、的外れのことを言っているかもしれませんが、上のXILINKのフォーラムのやり取りからリンクされている下の議論を見て思ったことです。

Can I "crash" instead of "hang" when an AXI transfer fails?
https://forums.xilinx.com/t5/Embedded-Linux/Can-I-quot-crash-quot-instead-of-quot-hang-quot-when-an-AXI/td-p/376079

(私の理解では)AXIインターコネクトを通じてPS (Processing System)とPL (Programmable Logic)がやり取りをするさいに、

  • データの読み出し時: PSからPLにデータアドレスを送ると、PLから読み出されたデータとRVALIDが返ってくる。
  • データの書き込み時: PSからPLにデータアドレスと書き込みデータを送ると、PLからBVALIDが返ってくる。
  • しかしPLがRVALIDやBVALIDを返さず、無応答だと、PSはハングアップする。

となるので、(もし私の勘違いでなければ)ハングアップの件はPL側の問題の可能性もあるのではないかと思います。

編集 履歴 (2)
  • gammodlerさんの3個目の投稿(2016/02/12)へのレスです。
    -
  • ハングアップに関する自分の認識について追記しました。 -

ハングアップの原因はよくわかりませんが、デバイスドライバは他のドライバのソースを参考にしつつ、一般的なやり方に従って書けばよさそうな気がします。

ところでネットで見ると「digilentのチュートリアル」が評判が良さそうです。私はやった訳ではないですが、見た感じでたぶん参考になりそうだと思ったので挙げておきます。

Embedded Linux® Hands-on Tutorial for the ZYBO をやってみた

記事中の「オフィシャルドキュメント」(pdf)へのリンクは残念なことに切れていますが、「ドラフト版」のリンク(下記)の方は現時点でアクセスできます。

Embedded Linux Tutorial - Zybo
http://www.instructables.com/id/Embedded-Linux-Tutorial-Zybo/

  • 上のURLにアクセスしても最初はチュートリアルの「Step 1: Download base system」しか表示されませんが、「View All Steps」をクリックするとチュートリアル全体が表示されます。または「Next」をクリックすると1ステップずつ進みます。
  • 「Step 42: Create myled.c」のところにデバイスドライバのソース(myled.c)へのリンクがあります。これを落として中身を読むと参考になると思います。request_mem_region()ioremap()iounmap()release_mem_region()iowrite32()の使い方のイメージがつかめます。
  • 「Step 44: Add myled to the Device Tree」でデバイスをDevice Treeに追加しています。I/Oメモリ領域の物理アドレスやサイズはその際にdtsファイル内に書き込んでいます。
  • チュートリアルはDevice Treeを使用していますが、gammodlerさんがやっているように物理アドレスをハードコードしても(テスト目的なら)別に構わないとは思います。

追記

ちなみに無限ループの話ですが、特に心配する必要はないと思います。

lib/iomap.cより

#define PIO_OFFSET  0x10000UL
#define PIO_MASK    0x0ffffUL
#define PIO_RESERVED    0x40000UL
...
static void bad_io_access(unsigned long port, const char *access)
{
    static int count = 10;
    if (count) {
        count--;
        WARN(1, KERN_ERR "Bad IO access at port %#lx (%s)\n", port, access);
    }
}

/*
 * Ugly macros are a way of life.
 */
#define IO_COND(addr, is_pio, is_mmio) do {         \
    unsigned long port = (unsigned long __force)addr;   \
    if (port >= PIO_RESERVED) {             \
        is_mmio;                    \
    } else if (port > PIO_OFFSET) {             \
        port &= PIO_MASK;               \
        is_pio;                     \
    } else                          \
        bad_io_access(port, #is_pio );          \
} while (0)
...
void iowrite32(u32 val, void __iomem *addr)
{
    IO_COND(addr, outl(val,port), writel(val, addr));
}

IO_CONDマクロがやっていること(iowrite32の場合)

  • iowrite32の場合はis_pioがoutl(val,port)に置き換わり、is_mmioがwritel(val, addr)に置き換わります。以下その前提です。
  • 指定されたアドレスがPIO_RESERVED (0x40000)以上だったら、writel(val, addr)を呼び出しメモリマップドI/Oを行ないます。
  • もしくは指定されたアドレスがPIO_OFFSET (0x10000)より大なら、outl(val,port)を呼び出しPIOを行ないます。しかしPIOの本当の範囲は0-0xffffですので、アドレスはPIO_MASK (0x0ffff)でマスクします。PIO_OFFSETがわかりにくいですが、おそらくI/OポートをI/Oメモリとして扱うために事前にioport_map()を呼んだときに、ポートにPIO_OFFSET (0x10000)を足していることが前提になっているのではないかと思います(あまり自信ありませんが)。
  • その他の場合は、bad_io_access()を呼び出します。
  • iowrite32()がこういう風になっているのはたぶん移植性とか汎用性のためと思います(違うかもしれません)。
  • ただし前述のようにARMの場合はwritel()outl()も最終的には最下位の_raw_write()を呼び出します(いずれにせよメモリマップドI/Oです)。
  • do-whileループを使っていますが、これはC言語のマクロで複数の文を一つのグループにまとめるための常套手段であり、while(0)なので、実際はループはしていません。なんでこんなことをするかというと、理由は下のページあたりを参照してください。
  • https://www.jpcert.or.jp/sc-rules/c-pre10-c.html
  • という訳で無限ループについて心配する必要はないと思います。
編集 履歴 (9)
  • 無限ループの件について追記しました。
    -
  • lib/iomap.cの引用部分にbad_io_accessも含めました。
    -

blunder3様

解決に苦慮するなか懇切な解説を頂き本当に感謝いたしております。
紹介していただいた平易なドキュメントも参考にさせていただきます。

Driver側から見て無限Loop要因はないことを指摘していただきこれを前提に検討を進めているのですが、実はHard側に要因がありうるのではないかと考えました。
現在AXI-BUSから引き出した信号線をmyIP側で
if (writeStb = '1' and writeStb'event) then
if (writeAddr = "0000") then
writeReg <= writeBus;
end if;
end if;
によりwriteRegにLatchしております。
以下推定、過程を前提にしてしまっているのですが、writeRegがDual PortのRegisterであった場合、書き込みAと読み出しB二つPortを備えています。AXI側がAにAddressをセットして書き込んだときBが同じアドレスを指していると、Bが別のAddressをpointしない限りARM CPUはProgram Counterを更新できません。つまり完全なHangUp状態となります。
これを思いついたのは過去にこのような事例に遭遇、原因究明に苦労した記憶があるからです。
解決策は最初からHard上でBをfloating状態にしておくことです。しかしDiscreteならともかくFPGA内ではどうすればいいのかわかりません。第一A,B Portを意識して使用していません。
hangUpはしますがwrite命令自体は実行され負荷のLED Lampが点灯します。
Hard上でオッシロであたったところ絶えず変化しているはずのwritAddr,writeBusがLevelになってしまっているのが観測されました。上記の推測に矛盾しません。
しかしAXI-BUSはPoint-to- Point conceptに基づく通常とは異なるBus、myIPにアクセスしていないときは変化がないのは正常なのかもしれません。
以上論点がHard寄りになってしまいました。上記の推論が正しいならソフト側から追求しても正解に至れません。

ご意見を伺えれば幸いです。

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。