PolarFire® SoCシリーズ③ コア間メモリ共有の方法

MSSの使い方

概要

はじめに

Microchip社のPolarFire® SoCは、不揮発性で低消費電力のミッドレンジSoC FPGAで、64ビットのRISC-V ISAを5コア搭載したプロセッサーと低消費電力FPGAを組み合わせたチップです。

この記事は、私自身の備忘録も兼ねて、PolarFire® SoCのMSS(Microprocessor Subsystem)における各種ペリフェラルの活用を目指して執筆しています。試行錯誤しながら実験を進めているため、内容に不備や不足がある可能性もございます。その際は、何卒ご容赦いただけますと幸いです。

(fig.1-1)PolarFire® SoC ブロック図

改定履歴

公開/変更日変更内容
25/1/31初版
メモリ共有の方法
25/6/11タイトル修正

外部リンク

タイトルリンク
PolarFire SoCプロダクトページ
(Microchip)
PolarFire® SoC FPGAs | Microchip Technology
PolarFire SoC Discoveryキット
(Microchip)
PolarFire® SoC Discovery Kit | Microchip Technology
PolarFire SoC MSS テクニカルリファレンスマニュアルPolarFire SoC MSS Technical Reference Manual (microchip.com)
Microprocessor Subsystem (MSS) User’s GuidePolarFire SoC MSS Technical Reference Manual (microchip.com)
PolarFire SoCプロダクトページ
(GitHub)
PolarFire-SoC · GitHub
ベアメタルプロジェクト
(Github)
GitHub – polarfire-soc/polarfire-soc-bare-metal-examples: Bare metal example software projects for PolarFire SoC
GPIO Bare Metal Driver
(Github)
polarfire-soc-documentation/bare-metal-embedded-software/bare-metal-driver-user-guides/polarfire-soc-mss-driver-user-guides/mss-gpio/mss-gpio-driver-user-guide.md at master · polarfire-soc/polarfire-soc-documentation · GitHub
(fig.1-2)各リンク集

3.構成

前回の記事と同じく、PolarFire® SoC Discovery Kitを使用し、動作を確認していきます。
PolarFire® SoC Discovery Kit | Microchip Technology

(fig.2-1)PolarFire® SoC Discovery Kit 外観

1.コア間のメモリ共有方法

0.はじめに

ベースプロジェクトは前回の記事と同様に「mpfs-gpio-interrupt」を使用します。

1.リンカースクリプトの設定

①リンカースクリプトを開きます

②メモリは以下の様に割り当てられております。

領域名先頭アドレスサイズ説明
envm0x20220100128k – 0x100envm(Embedded Non-Volatile Memory)は不揮発性メモリで、通常プログラムコード(ファームウェア)が格納される領域です。
switch_code_dtim0x01001C001kクロック切り替え時に使用されるコードを配置するため
dtim0x010000007kデータ用のメモリ領域で、データまたはスタック領域として使用されます。
e51_itim0x0180000028kE51コア用の命令およびデータメモリ(ITIM: Instruction Tightly Integrated Memory)
u54_x_itim0x01808000,
0x01810000,
0x01818000,
0x01820000
28k各U54コアに割り当てられたITIM
l2lim0x08000000512kL2キャッシュを統合した共有メモリ領域で、データや共有メモリとして利用されます
scratchpad0x0A000000512k汎用のオンチップRAM
ddr_cached_32bit0x80000000128M高速アクセスが求められるコードやデータの格納に使用
キャッシュが有効のためデータの一貫性が重要な場合は注意が必要
ddr_non_cached_32bit0xC0000000128M周辺機器(DMAコントローラなど)が直接アクセスするメモリとして利用。キャッシュが無効なので、データの一貫性を保つ必要がある場合に使用
ddr_wcb_32bit0xD0000000256M書き込みパフォーマンスを向上させるためのメモリ領域。
グラフィック処理や連続したデータ書き込みが発生する場合に最適です。
ddr_cached_38bit0x1000000000896M38ビットアドレス空間でキャッシュが有効なメモリ。大規模なデータセットや複雑なアプリケーション用。38ビットアドレス空間を使用するため、メモリ管理ユニット(MMU)が必要です。
ddr_non_cached_38bit0x1400000000896M周辺機器やリアルタイム処理に使用。
キャッシュが無効なので、データの一貫性が保たれます。


④共有変数用のセクションをリンカースクリプトに追加します。このセクションを l2lim セクション内に配置します。

.shared_data : ALIGN(0x10)
{
    __shared_data_start = .;
    *(.shared_data)
    . = ALIGN(0x10);
    __shared_data_end = .;
} > l2lim

⑤また共有メモリをゼロクリアするため、 .bss の一部としてゼロクリアさせます。

 .bss : ALIGN(0x10)
{ 
    __bss_start = .;
    *(.bss .bss.* .gnu.linkonce.b.*)
    *(.shared_data)
    . = ALIGN(0x10);
    __bss_end = .;
} > l2lim

2.変数宣言

共有変数を配置するには、ソースコードで変数に特定のセクションを指定する必要があります。
u54_1.cの先頭で宣言します。

__attribute__((section(".shared_data")))
volatile uint32_t shared_var1;

__attribute__((section(".shared_data")))
volatile uint32_t shared_var2[10];

3.ソースファイルの変更

①src > application > hart1 > u54_1.cをダブルクリックで開きます。

②125行目あたりに//ここから挿入 ~ //ここまでをペーストします。

    SYSREG->GPIO_INTERRUPT_FAB_CR = 0xFFFFFFFFUL;

    PLIC_SetPriority_Threshold(0);

    for (int_num = 0u; int_num <= GPIO2_NON_DIRECT_PLIC; int_num++)
    {
        PLIC_SetPriority(GPIO0_BIT0_or_GPIO2_BIT0_PLIC_0 + int_num, 2u);
    }

    
    //ここから挿入
    uint64_t led_cnt;
    MSS_GPIO_config(GPIO1_LO, MSS_GPIO_9, MSS_GPIO_OUTPUT_MODE);
    while(1u)
    {
        led_cnt ++;
        if (led_cnt < 500000)
        {
            MSS_GPIO_set_output(GPIO1_LO, MSS_GPIO_9, 1u);
           // led_cnt = 1;
        }
        else if (led_cnt < 1000000)
        {
            MSS_GPIO_set_output(GPIO1_LO, MSS_GPIO_9, 0u);
           // led_cnt = 0;
        }
        else
        {
            led_cnt = 0;
        }

    shared_var1 = led_cnt;
    }
    //ここまで
    
    
    
    MSS_GPIO_init(GPIO2_LO);

    for (cnt = 9u; cnt< 23u; cnt++)
    {
        MSS_GPIO_config(GPIO2_LO,
                        cnt,
                        MSS_GPIO_OUTPUT_MODE);
    }

    MSS_GPIO_config(GPIO2_LO, MSS_GPIO_26,

③src > application > hart1 > u54_2.cをダブルクリックで開きます。

④22行目からのメインコードを以下の様に書き換えます。
デフォルトではコアを低電力状態にし、メインコア(e51.c)からの起動を待つようになっていますので
コメントアウトします。
ループ内で icount = shared_var1; の様に共有メモリにアクセスします。

void u54_2(void)
{
    uint64_t hartid = read_csr(mhartid);
    volatile uint32_t icount = 0U;

    /* Clear pending software interrupt in case there was any.
       Enable only the software interrupt so that the E51 core can bring this
       core out of WFI by raising a software interrupt. */

 //   clear_soft_interrupt();
 //   set_csr(mie, MIP_MSIP);

    /* Put this hart in WFI */

 //   do
//    {
 //       __asm("wfi");
 //   }while(0 == (read_csr(mip) & MIP_MSIP));

    /* The hart is out of WFI, clear the SW interrupt. Here onwards application
     * can enable and use any interrupts as required */

 //   clear_soft_interrupt();

 //   __enable_irq();


    while (1U)
    {
        icount = shared_var1;
        if (0x100000U == icount)
        {
            icount = 0U;
        }
    }

    /* never return */
}

なお、コアが同時に書き込むなど競合が発生する可能性がありますので、セマフォなどでアクセス制御をするべきだと思います

編集後記

正直なところ、まだわからないことが多く、手探りで実験を進めている状態です。ドキュメントは多く揃っているものの、その分資料やページの量が膨大で初めて扱う内容も多いため、情報の整理に苦労しています。


コメント

タイトルとURLをコピーしました