CC-RXもGNURXもC99仕様では_Pragmaプリプロセッサ演算子というものが使えるのですね(FITのコンパイラ対応の効率化に役立ちそうかも)

こんにちは。NoMaYです。

別スレッド『Amazon FreeRTOSだそうです。ルネサスさんのRXは参加しないのかな?』でCC-RX用プロジェクトをGNURX用プロジェクトへ移植する作業をぽつりぽつりとやっていて、CC-RXの#pragma pack / #pragma packoption相当のものとしてGNURXで#pragma pack(1) / #pragma pack()が使えることに気付いたのですが、たまたま同じタイミングで更に別スレッドの作業をやっていてGNURXで#pragma address 変数名 アドレスという記述が使えるらしいことに気付き、調べているうちにFITが前提としているC99仕様では_Pragmaプリプロセッサ演算子(関連リンク参照)というものが使えることを知りました。_Pragmaを使うと以下のように#pragmaをプリプロセッサで扱うことが出来るようになり、FITのコンパイラ対応の効率化に役立ちそうかも知れないと思いました。

#define R_PRAGMA(...) _Pragma(#__VA_ARGS__)

#if defined(__CCRX__)

#define R_PRAGMA_PACK       R_PRAGMA(pack)
#define R_PRAGMA_PACKOPTION R_PRAGMA(packoption)

#elif defined(__GNUC__)

#define R_PRAGMA_PACK       R_PRAGMA(pack(1))
#define R_PRAGMA_PACKOPTION R_PRAGMA(pack())

#endif
/*
 * EDMAC descriptor as defined in the hardware manual. It is
 * modified to support little endian CPU mode.
 */
    R_PRAGMA_PACK

typedef struct DescriptorS
{
    __evenaccess uint32_t           status;
    #if __LIT
    /* Little endian */
    __evenaccess uint16_t           size;
    __evenaccess uint16_t           bufsize;
    #else
    /* Big endian */
    __evenaccess uint16_t bufsize;
    __evenaccess uint16_t size;

    #endif
    uint8_t            *buf_p;
    struct DescriptorS *next;
} descriptor_t;

/*
 * Ethernet buffer type definition.  
 */
typedef struct EtherBufferS
{
    uint8_t buffer[EMAC_NUM_BUFFERS][ETHER_CFG_BUFSIZE];

} etherbuffer_t;

typedef struct pause_resolutionS
{
    pausemask_t mask;
    pauseval_t  value;
    uint8_t     transmit;
    uint8_t     receive;
} pauseresolution_t;

typedef struct
{
    volatile struct st_etherc __evenaccess * petherc; /* ETHERC module */
    volatile struct st_edmac __evenaccess * pedmac; /* EDMAC */
    volatile uint32_t         __evenaccess * preg_pir;
    uint32_t                  phy_address;
    uint8_t                   port_connect;
} ether_control_t;

typedef struct
{
    const ether_control_t * pether_control;
    uint32_t              phy_access;
} ether_ch_control_t;

    R_PRAGMA_PACKOPTION

[関連リンク]

クローバーフィールド.jp/_pragma演算子を使ってみた。
embedded.cloverfield.jp/2016/04/12/_pragma演算子ではまりました。
infocenter.arm.com/help/topic/com.arm.doc.dui0472ij/BABDIJDD.html
cpprefjp.github.io/lang/cpp11/pragma_operator.html
Google検索: _Pragma

[補足]

gcc-renesas.comのドキュメントには記載無いがGCC本家のドキュメントの#pragma pack(1) / #pragma pack()が使えました。(実はiodefine.hでも使われていました。)

GNURX
gcc-renesas.com/migration-guides/rx/index.html#Compiler_directives

GCC本家
gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Structure_002dPacking-Pragmas.html#Structure_002dPacking-Pragmas
 

Parents
  • こんにちは。NoMaYです。

    今度は#pragma inlineについて考えてみました。CC-RXのヘルプを読んでいて気付いたことは、FITが前提としているC99仕様では、以下のようなCC-RXとGNURXに共通なマクロを用意するのが良いのではないかということです。

    #define R_ATTRIB_INLINE        inline extern
    #define R_ATTRIB_STATIC_INLINE inline static
    #define R_PRAGMA_INLINE(function_prototype)        R_ATTRIB_INLINE function_prototype;
    #define R_PRAGMA_STATIC_INLINE(function_prototype) R_ATTRIB_STATIC_INLINE function_prototype;

    そうすれば、以下のようなCC-RXとGNURXで共通な記述に出来ると思います。(ただ、この関数に限りませんが、ファイル間インライン展開される為にはコンパイル時に大域最適化オプション-merge_filesが必要だという点がFITのプログラマの人達に認識されていないような気がします。この件はスレッドを分けようかと思います。[追記] 別スレッド『FITのソースを見ていて気付いたCC-RXの仕様をプログラマが勘違いしている気がするコード』に分けました。)

    例) r_sci_rx.c

    現状

    #pragma inline(R_SCI_GetVersion)
    uint32_t  R_SCI_GetVersion(void)
    {
    uint32_t const version = (SCI_VERSION_MAJOR << 16) | SCI_VERSION_MINOR;

        return version;
    } /* End of function R_SCI_GetVersion() */

    共通化案

    R_PRAGMA_INLINE(uint32_t R_SCI_GetVersion(void))
    uint32_t  R_SCI_GetVersion(void)
    {
    uint32_t const version = (SCI_VERSION_MAJOR << 16) | SCI_VERSION_MINOR;

        return version;
    } /* End of function R_SCI_GetVersion() */

    もしくは

    R_ATTRIB_INLINE
    uint32_t  R_SCI_GetVersion(void)
    {
    uint32_t const version = (SCI_VERSION_MAJOR << 16) | SCI_VERSION_MINOR;

        return version;
    } /* End of function R_SCI_GetVersion() */

    以下のCC-RXのC99仕様のinline指定子に関する赤文字の挙動はGNURXでも同じ(というか常に生成される?)でした。([追記] 念の為に確認したらCC-RXでも常に生成されたので調べてみたら、プロトタイプ宣言があった場合にも生成されるようでした。)

    4.2.4 拡張仕様の使用方法 - CS+ V6.01.00 > コンパイラ編 > コンパイラ言語仕様 > 拡張言語仕様 > 拡張仕様の使用方法
    (4)関数のインライン展開記述
    tool-support.renesas.com/autoupdate/support/onlinehelp/ja-JP/csp/V6.01.00/CS+.chm/Compiler-CCRX.chm/Output/ccrx04c0204y.html#19230


    今までに投稿した内容を組み込んで、以下のヘッダファイルを作成してみました。

    SCFGcompiler.h

    1207.SCFGcompiler_h_20180708.txt
    #ifndef SCFGCOMPILERS_H
    #define SCFGCOMPILERS_H
    
    /*
    https://gcc-renesas.com/migration-guides/rx/index.html#Compiler_directives
    
    https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
    https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
    https://gcc.gnu.org/onlinedocs/gcc/RX-Function-Attributes.html
    
    https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
    https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html
    */
    
    #if defined(__CCRX__)
        /* supported */
    #elif defined(__GNUC__)
        /* supported */
    #else
        #error "Unrecognized compiler"
    #endif
    
    #define R_PRAGMA(...) _Pragma(#__VA_ARGS__)
    
    #if defined(__CCRX__)
    
    #define R_PRAGMA_PACK       R_PRAGMA(pack)
    #define R_PRAGMA_PACKOPTION R_PRAGMA(packoption)
    
    #elif defined(__GNUC__)
    
    #define R_PRAGMA_PACK       R_PRAGMA(pack(1))
    #define R_PRAGMA_PACKOPTION R_PRAGMA(pack())
    
    #endif
    
    #if defined(__CCRX__)
    
    #define R_PRAGMA_INTERRUPT(function_name, vector)           R_PRAGMA(interrupt function_name(vect=vector))\
    extern void function_name(void);
    #define R_PRAGMA_STATIC_INTERRUPT(function_name, vector)    R_PRAGMA(interrupt function_name(vect=vector))\
    static void function_name(void);
    
    //TODO: fast interrupt
    
    #elif defined(__GNUC__)
    
    #define R_PRAGMA_INTERRUPT(function_name, vector)           extern void function_name(void) __attribute__((interrupt(".rvectors", vector)));
    #define R_PRAGMA_STATIC_INTERRUPT(function_name, vector)    static void function_name(void) __attribute__((interrupt(".rvectors", vector), used));
    
    //TODO: fast interrupt
    
    #endif
    
    #define R_ATTRIB_INLINE        inline extern
    #define R_ATTRIB_STATIC_INLINE inline static
    #define R_PRAGMA_INLINE(function_prototype)        R_ATTRIB_INLINE function_prototype;
    #define R_PRAGMA_STATIC_INLINE(function_prototype) R_ATTRIB_STATIC_INLINE function_prototype;
    
    #if defined(__CCRX__)
    
        /* nothing to do */
    
    #elif defined(__GNUC__)
    
    #define __evenaccess /* none */
    
    #endif
    
    /*
    https://gcc-renesas.com/migration-guides/rx/index.html#Compiler_predefined
    */
    
    #if defined(__CCRX__)
    
        /* maybe nothing to do */
    
    #elif defined(__GNUC__)
    
    #define __RX 1
    
    #if defined(__RX_LITTLE_ENDIAN__)
    #define __LIT 1
    #endif
    
    #if defined(__RX_BIG_ENDIAN__)
    #define __BIG 1
    #endif
    
    #endif
    
    #endif /* SCFGCOMPILERS_H */
    

     

Reply
  • こんにちは。NoMaYです。

    今度は#pragma inlineについて考えてみました。CC-RXのヘルプを読んでいて気付いたことは、FITが前提としているC99仕様では、以下のようなCC-RXとGNURXに共通なマクロを用意するのが良いのではないかということです。

    #define R_ATTRIB_INLINE        inline extern
    #define R_ATTRIB_STATIC_INLINE inline static
    #define R_PRAGMA_INLINE(function_prototype)        R_ATTRIB_INLINE function_prototype;
    #define R_PRAGMA_STATIC_INLINE(function_prototype) R_ATTRIB_STATIC_INLINE function_prototype;

    そうすれば、以下のようなCC-RXとGNURXで共通な記述に出来ると思います。(ただ、この関数に限りませんが、ファイル間インライン展開される為にはコンパイル時に大域最適化オプション-merge_filesが必要だという点がFITのプログラマの人達に認識されていないような気がします。この件はスレッドを分けようかと思います。[追記] 別スレッド『FITのソースを見ていて気付いたCC-RXの仕様をプログラマが勘違いしている気がするコード』に分けました。)

    例) r_sci_rx.c

    現状

    #pragma inline(R_SCI_GetVersion)
    uint32_t  R_SCI_GetVersion(void)
    {
    uint32_t const version = (SCI_VERSION_MAJOR << 16) | SCI_VERSION_MINOR;

        return version;
    } /* End of function R_SCI_GetVersion() */

    共通化案

    R_PRAGMA_INLINE(uint32_t R_SCI_GetVersion(void))
    uint32_t  R_SCI_GetVersion(void)
    {
    uint32_t const version = (SCI_VERSION_MAJOR << 16) | SCI_VERSION_MINOR;

        return version;
    } /* End of function R_SCI_GetVersion() */

    もしくは

    R_ATTRIB_INLINE
    uint32_t  R_SCI_GetVersion(void)
    {
    uint32_t const version = (SCI_VERSION_MAJOR << 16) | SCI_VERSION_MINOR;

        return version;
    } /* End of function R_SCI_GetVersion() */

    以下のCC-RXのC99仕様のinline指定子に関する赤文字の挙動はGNURXでも同じ(というか常に生成される?)でした。([追記] 念の為に確認したらCC-RXでも常に生成されたので調べてみたら、プロトタイプ宣言があった場合にも生成されるようでした。)

    4.2.4 拡張仕様の使用方法 - CS+ V6.01.00 > コンパイラ編 > コンパイラ言語仕様 > 拡張言語仕様 > 拡張仕様の使用方法
    (4)関数のインライン展開記述
    tool-support.renesas.com/autoupdate/support/onlinehelp/ja-JP/csp/V6.01.00/CS+.chm/Compiler-CCRX.chm/Output/ccrx04c0204y.html#19230


    今までに投稿した内容を組み込んで、以下のヘッダファイルを作成してみました。

    SCFGcompiler.h

    1207.SCFGcompiler_h_20180708.txt
    #ifndef SCFGCOMPILERS_H
    #define SCFGCOMPILERS_H
    
    /*
    https://gcc-renesas.com/migration-guides/rx/index.html#Compiler_directives
    
    https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
    https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
    https://gcc.gnu.org/onlinedocs/gcc/RX-Function-Attributes.html
    
    https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
    https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html
    */
    
    #if defined(__CCRX__)
        /* supported */
    #elif defined(__GNUC__)
        /* supported */
    #else
        #error "Unrecognized compiler"
    #endif
    
    #define R_PRAGMA(...) _Pragma(#__VA_ARGS__)
    
    #if defined(__CCRX__)
    
    #define R_PRAGMA_PACK       R_PRAGMA(pack)
    #define R_PRAGMA_PACKOPTION R_PRAGMA(packoption)
    
    #elif defined(__GNUC__)
    
    #define R_PRAGMA_PACK       R_PRAGMA(pack(1))
    #define R_PRAGMA_PACKOPTION R_PRAGMA(pack())
    
    #endif
    
    #if defined(__CCRX__)
    
    #define R_PRAGMA_INTERRUPT(function_name, vector)           R_PRAGMA(interrupt function_name(vect=vector))\
    extern void function_name(void);
    #define R_PRAGMA_STATIC_INTERRUPT(function_name, vector)    R_PRAGMA(interrupt function_name(vect=vector))\
    static void function_name(void);
    
    //TODO: fast interrupt
    
    #elif defined(__GNUC__)
    
    #define R_PRAGMA_INTERRUPT(function_name, vector)           extern void function_name(void) __attribute__((interrupt(".rvectors", vector)));
    #define R_PRAGMA_STATIC_INTERRUPT(function_name, vector)    static void function_name(void) __attribute__((interrupt(".rvectors", vector), used));
    
    //TODO: fast interrupt
    
    #endif
    
    #define R_ATTRIB_INLINE        inline extern
    #define R_ATTRIB_STATIC_INLINE inline static
    #define R_PRAGMA_INLINE(function_prototype)        R_ATTRIB_INLINE function_prototype;
    #define R_PRAGMA_STATIC_INLINE(function_prototype) R_ATTRIB_STATIC_INLINE function_prototype;
    
    #if defined(__CCRX__)
    
        /* nothing to do */
    
    #elif defined(__GNUC__)
    
    #define __evenaccess /* none */
    
    #endif
    
    /*
    https://gcc-renesas.com/migration-guides/rx/index.html#Compiler_predefined
    */
    
    #if defined(__CCRX__)
    
        /* maybe nothing to do */
    
    #elif defined(__GNUC__)
    
    #define __RX 1
    
    #if defined(__RX_LITTLE_ENDIAN__)
    #define __LIT 1
    #endif
    
    #if defined(__RX_BIG_ENDIAN__)
    #define __BIG 1
    #endif
    
    #endif
    
    #endif /* SCFGCOMPILERS_H */
    

     

Children
No Data