小さなアカデミック OS を TriCore から ARM Cortex (Thumb-2 命令セット) に移植しています。スケジューラが機能するためには、スタックやリンク レジスタを変更せずに別の関数に直接 JUMP する必要がある場合があります。
TriCore (またはむしろ tricore-g++) では、このラッパー テンプレート (任意の 3 つの引数関数) が機能します。
template< class A1, class A2, class A3 >
inline void __attribute__((always_inline))
JUMP3( void (*func)( A1, A2, A3), A1 a1, A2 a2, A3 a3 ) {
typedef void (* __attribute__((interrupt_handler)) Jump3)( A1, A2, A3);
( (Jump3)func )( a1, a2, a3 );
}
//example for using the template:
JUMP3( superDispatch, this, me, next );
これにより、 の代わりにアセンブラ命令J
(別名 JUMP)が生成さCALL
れ、(それ以外の場合は通常の) C++ 関数にジャンプするときに、スタックと CSA は変更されませんsuperDispatch(SchedulerImplementation* obj, Task::Id from, Task::Id to)
。
ここで、ARM Cortex (または、arm-none-linux-gnueabi-g++) で同等の動作が必要です。つまり、 (リンクと交換を伴うB
BRANCH) の代わりに (別名 BRANCH) 命令を生成します。BLX
しかしinterrupt_handler
、arm-g++ には属性がなく、同等の属性が見つかりませんでした。
だから私asm volatile
はasmコードに頼って直接書いてみました:
template< class A1, class A2, class A3 >
inline void __attribute__((always_inline))
JUMP3( void (*func)( A1, A2, A3), A1 a1, A2 a2, A3 a3 ) {
asm volatile (
"mov.w r0, %1;"
"mov.w r1, %2;"
"mov.w r2, %3;"
"b %0;"
:
: "r"(func), "r"(a1), "r"(a2), "r"(a3)
: "r0", "r1", "r2"
);
}
これまでのところ、少なくとも私の理論では、とても良いです。Thumb-2 では、関数の引数をレジスタ (この場合は r0..r2) で渡す必要があるため、動作するはずです。
しかし、その後リンカーは死ぬ
undefined reference to `r6'
asmステートメントの閉じ括弧に...そして、どうすればよいかわかりません。OK、私は C++ の専門家ではありません。asm 構文はあまり単純ではありません。arm-g++ を修正__attribute__
するためのヒントは 1 つの方法であり、asm コードを修正するためのヒントは別の方法です。a1..a3
もう1つの方法は、asmステートメントが入力されたときにすでにレジスターにある必要があることをコンパイラーに伝えることr0..r2
です(少し調べましたが、ヒントは見つかりませんでした)。