Polling routine または Differed call を設ける。
----------
#include <DlyState.h>
#include <PcContex.h>
staic void polling(void) または #include <Differed.h>
#include <VTable.h>
---------

polling routine を使わない時は
    #define DfUseMyDpc  /* PcLoop.h にある polling() を使わない*/
    voidpolling(){}
を作る。if ( pointerPolling ){ polling();} と記述するより、早いコードになる
                          C1┌────────┐              C6┌───────────┐
                              │StStateDelay    │                  │StVTable              │
                              ├────────┤              *   ├───────────┤
                              │wdDelay:12bit   │←───────◇│static StVTable m_list│
                              │m_enPCState:3bit│                  │m_pContextVd          │
                              │m_blReady:1bit  │                  │m_ppStVTableNext      │
                              ├────────┤                  ├───────────┤
                              │setDelay()      │                  │m_pfPolling           │
                              │DecrementDelay()│                  │m_pfCheckAndExecute   │
                              │setReturnState()│                  │[checkAndExecute()]   │
                              │terminate()     │                  │                      │
                              └────────┘                  └───────────┘
                                    △
          ┌────────────┼─────────────┬────────────┐
┌────┴────┐┌──────┴─────┐┌──────┴─────┐┌─────┴─────┐
│ StTimeUpContext  ││PcOOP                   ││PcLpOOP                 ││StJmpBfContext        │
├─────────┤├────────────┤├────────────┤├───────────┤
│ m_pTimeUpAddress ││m_pTimeUpAddress        ││m_pTimeUpAddress        ││                      │
│                  ││mimimum compiler context││mimimum compiler context││jum_buf context       │
├─────────┤├────────────┤├────────────┤├───────────┤
│                  ││start()                 ││start()                 ││start()               │
│                  ││delay()                 ││delay()                 ││delay()               │
│                  ││restart()               ││restart()               ││restart()             │
│ doAtTimeUp()     ││checkAndExecute()       ││checkAndExecute()       ││checkAndExecute()     │
└─────────┘└────────────┘└────────────┘└───────────┘
C2                      C3    △                       C4 △                       C5
                      ┌─────┴─────┐    ┌─────┴─────┐
                      │StStackContext        │    │StStackContext        │
                      ├───────────┤    ├───────────┤
                      │int inArStack[]       │    │int inArStack[]       │
                      ├───────────┤    ├───────────┤
                  C6│call(..)              │C7│call(..)              │
                      └───────────┘    └───────────┘
                       PcOOP.h はなくなった。DfUseMyDpc を宣言することで 
                       PcLpOOP に PcOOP.h の役目をさせる。
                                               
    1 StTimeUpContext では doAtTimeUp() を checkAndExecute() の変わりに使う。
      StTimeUpContext では m_enCntxtState を使わない。doAtTimeUp() は呼び出
      されても、コンテキスト・スイッチを行うことなく戻ってしまうからである。
    2 task(StVTable* pStVTable) の形式とする。開始する時 pStVTable 変数を実際に設定する
    3 context switch を伴う関数 pf を呼び出す時は 
            call(pf, StVTable* pStVTable, argv[1],argv[2],...)
      と呼び出す。呼び出される context switch を伴う関数は
            pf(StVTable* pStVTable, argv[1], argv[2],...)
      のプロトタイプを持つ。

    C3:stack context を共用する
          コンテキスト・スイッチを伴うサブルーチンを使わない。
          または コンテキスト・スイッチでは return の変わりに gotoMain() を使う
    
    生々消滅するタスクを統一して扱う。(生成消滅はリストへの追加と削除で実装する。)
    C++ ならば 継承、Has a 関係、strategy pattern で明確に記述できる構造が、が渾然と組み込まれている。

使用上の Tips

  1. task を開始する時にパラメータを渡したければ、StDelayAndContext の void 引数の最後に parameter 要素を追加する。
  2. IntCntxt で suspend(.)/restart(.) を共用するため、m_pStStateDelay が 0 であることを判定して、処理を分ける。
  3. terminate() は呼び出し元に戻ってくる。そうすることで汎用性を持たせる。C の return 命令によってコンテキスト・スイッチ側に戻す。
  4. task の this 引数 struct StDelayPcContext* pStDelayPcContextAg はスタックポインタの下限も示す。

コーディングでの注意点

  1. PcCntxt_start(struct StDelayPcContext*)、DlyState_setRestartState(., .) は割り込みからも呼べるようにする。そのために、terminate は m_enCntxtState と m_blReady を同時にクリアする。PcCntxt_start,DlyState_setRestartState は m_blReady を設定してから m_enCntxtState を設定する。
  1. startImmediately(), restartImmediately() によるタスクへの CPU 占有権の移動を活用する

モニタの考え方

  1. task を終了するために明示的に DlyState_terminate(.) を呼び出す。タスク・サブルーチンの中で自分を終了させることもあるので、return だけで勝手に terminate させてはまずい。
  2. DlyState_terminate() は呼び出した側に戻ってくる。
  3. StJmpBfContext では terminate() は longjmp(.) を実行してコンテキストを checkAndExecute(.) 呼び出しの直前に戻す。
  4. PcCntxt_suspend( const struct StDelayPcContext** ppStAg); とする。ppStAg は suspend が戻るべきアドレスの存在位置を示すからである。<-- これは bp が示している。78K コンパイラとの互換性のためだけである。
  5. 現在 Run 中のタスクに対して、自分でしか delay, suspend を行えない。でも StPcCntxt* 引数を使う。
  1. DlyState_whatState(.) は m_blReady, m_enCntxtState を一まとめにして返す。restart した後には wait 中の処理をさせないためである。
  2. EnStart によってタスクを開始するとき、または PcCntxt_startImmediately(.) によってタスクをもか縊死するとき、delay は 0 にされる。DlyState_setRestartState(.) または、PcCntxt_restartImmediately(.) によってリスタートさせるときは、delay は前の値が、残ったままである。再度 suspend(.) を実行すると、time up も働く。

suspend(StDelayPcContext**) call(←**)と引数を一つに限定する理由(


  1. 通常のコンテキスト・スイッチ以外に、割り込みルーチンでも呼び出される。
  2. task 関数自体を割り込みルーチンが呼び出すこともある。
  3. これらの動作をできるだけ多くの CPU/compiler で共通に動作するようにしておきたい。
  4. 応答 speed を犠牲にしても単純なコンテキスト・スイッチを選択する
  5. すべてのタスクでのスタック構造を同じにしておきデバッグを容易にする

df... を使う理由


    dfDelay(30);-->
        DlyState_setDelay((struct StDelayAndContext*)pStDelayPcContextAg,30);
        PcCntxt_suspend( &pStDelayPcContextAg );

    dfTerminate();->
         DlyState_terminate((struct StDelayAndContext*)pStDelayPcContextAg)
のようなキャスティングをかけたり、Dly.___ の関数名を引っ張り出したりが面倒である。

スタックを共用するコンテキスト・スイッチ at VC5.0/6.0


基準位置 HLret2 は、割り込み処理の最中の相対位置として決まる。固定されない。 inDamieAt[] は必要に応じてユーザーが設定する。ユーザーが使用するタスク・サブルーチンの引数の数によって定まる。
← Interrupt Task Subroutine は StPcContext が局所化される。アプリケーションごとに StPcContext を継承して拡張できる。そこに引数の働きをする変数領域を定義できる。
DfIntrStart()  intrTask(0) での SP データ構造
        auto variable
        ebp
        return address
        damie pStIntrCntxtAg
        damie value
                 <-- IntCntxt_suspend(.) を呼び出す前に SP が差していた

TyByte PcCntxt_suspend( const struct StDelayPcContext** ) での SP データ構造
PcCntxt_suspend を呼ぶ前
 EAX = 00408168 EBX = 7FFDF000 ECX = 0040A914
 EDX = 00004003 ESI = 00000000 EDI = 00000000
 EIP = 004063F8 ESP = 0012FF40 EBP = 0012FF48
 EFL = 00000212 CS = 001B DS = 0023 ES = 0023
 
 0x12ff34: タスクの di:0x000000
 0x12ff34: タスクの si:0x000000
 0x12ff34: タスクの bx:0x7ffdf000
 0x12ff34: タスクの cx:0x12ff50 <-- mov cx,lea[pStDelayPcContextAg], push cx を行った後だ
 0x12ff34: タスクの bp:0x12ff48
 0x12ff38: return address: 0x00046401
 0x12ff40: &pStDelayPcContextAg
 


TyByte PcCntxt_return2Task(const struct StDelayPcContext* pStDelayPcContextAg)
を呼ぶ前
 EAX = 00000000 EBX = 7FFDF000 ECX = 0040BC7C
 EDX = 0040BC7C ESI = 00000000 EDI = 00000000
       00409168
 EIP = 00401E5A ESP = 0012FF40 EBP = 0012FF58
 EFL = 00000293 CS = 001B DS = 0023 ES = 0023

      0x0012ff04: edi
      0x0012ff08: esi
      0x0012ff0c: ebx
ESP-->0x0012ff10:           ESP -= -24
                                                     <-- auto variable 領域

EBP-->0x0012ff34: 0x0012ff58 == EBP                  <-- return2Task(.) は、この上で動作する
      0x0012ff38: 0x00401e63 == return address         
      0x0012ff3c: 0x00409168 == pStDelayAndContextAg <-- &pStStackAndContextAg はここを指している
      0x0012ff40: 0x???????? == inDamieAt[0] == 3
           ・         ・             ・
      0x0012ff50: 0x???????? == inDamieAt[4] == 0


144:      return 0;   // damie return to avoid  warning

参考

00401E12   xor         al,al
00401E14   pop         edi │
00401E15   pop         esi │<-- この三つは __asm{...} を加えるだけで追加される
00401E16   pop         ebx │
00401E17   mov         esp,ebp
00401E19   pop         ebp
00401E1A   ret

    mov eax,dword ptr[cppStAg] は ebp に対するオフセットとして判定されている。ebp の値をマニュアルで
    変更すると、デバッガの変数が追従して変わってしまう。

          │              │←-- m_pTimeUpAddress を入れる。
          ├───────┤        sp をこの位置に設定する ret でタスク側に  context switch
0x12ff00  │   edi        │ ←┐ sp = 
          ├───────┤   │      
          │   esi        │   │
          ├───────┤   │
          │   ebx        │   │← 0x4067ed m_pTimeUpAddress
          ├───────┤   │
0x12ff0c  │pStPcContextAt     │
          ├───────┤   │                                   
          │pStStateDelayAt    │←タスク側に戻って add esp,4 を終わった後の sp
          ├───────┤   │  但しタスク側では edi, esi, ebx の push はなく、
          │byReturnValueAt    │  inAt, chAt の二つのオート変数を使っている 
          ├───────┤   │                                   
          │bp of PcCntxt_return2Task をここに移動する。== BPret2 │
          ├───────┤                                      │
          │PcCntxt_return2Task(.) への return address            │
(0x401eb2)├───────┤                                      │
0x12ff20●│pStDelayPcContextAg│of PcCntxt_return2Task(.) SPref2 │                  
(0x40bc40)├───────┤   ↓                                 │                        
          │inDamieAt in PcCntxt_executeLoopPolling(.)            │
          ├───────┤                                      │
          │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │これに対する相対位置に
          ├───────┤                                      │タスク側のデータを
          │return address│                                      │設定する処理を、
          ├───────┤                                      │PcCntxt_return2Task()
          │              │                                       が行う。

ここまでは task(.)
と同じスタック・フレーム
構造となる。


PcCntxt_return2Task()
を呼び出すことで作られ 
る Stack データ構造。

EnStart)

          ├───────┤   │                                   
          │bp of PcCntxt_return2Task をここに移動する。== BPret2 │
          ├───────┤                                      │
          │PcCntxt_return2Task(.) への return address            │
(0x401eb2)├───────┤                                      │
0x12ff20●│pStDelayPcContextAg│of PcCntxt_return2Task(.) SPref2 │                  
(0x40bc40)├───────┤   ↓                                 │                        
          │pVdDamieAt[3] │
          ├───────┤                                      │
          │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │これに対する相対位置に

void PcCntxt_saveContext(int* pInTaskSp では

    pStPcContextAt->m_inEBP_ESP 
            = ((int)PcCntxt_ppStExecutingCntxt) - 8 - ((int)pInTaskSp);

と計算してスタック・フレームを保存する

return2Os(void) saveContext(const struct StDelayPcContext* pStDelayPcContextAg)

struct StDelayPcContext** PcCntxt_ppStExecutingCntxt を使ったときの

int PcCntxt_delay(TyWord wdDelayAg)



VC++ Dfcall(kc struct StStackAndContext**, ku(*pfAg)(.), arg1, arg2, arg3, arg4, arg5...


      task stack

      │              │
      ├───────┤
      │User Auto Var │
      ├───────┤
      │StPcContext   │← pStPcContextAt
      ├─          ─┤
      │   ・         │
      ├─          ─┤
      │              │
      ├───────┤
      │StPcContext   │
      ├─          ─┤
      │   ・         │
      ├─          ─┤
      │              │
      ├───────┤

        void StkCntxt_setCallPrm(,void(*pfAg)(const struct StStackAndContext*,...)
                ,const struct StStackAndContext** cppStStackAndContextAg,... )
        
      │              │
      ├───────┤
      │pBpPcCntxt_return2TaskAt ← SP
      ├───────┤
      │bp            │
      ├───────┤                                        
      │StkCntxt_setCallPrm(.) 呼び出し側への return address    
      ├───────┤                                        
      │ pfAg                                                 
      ├───────┤                                      
      │←cppStStackAndContextAg of StkCntxt_setCallPrm(.) 
      ├───────┤                                      
    ││inArg 1 of  StkCntxt_setCallPrm(.)                    │
    ││───────┤                                      │
    ││inArg 2 of  StkCntxt_setCallPrm(.)                    │StkCntxt_setCallPrm()
copy│├───────┤                                      │を呼び出すことで作られ
┌─┤│inArg 3 of  StkCntxt_setCallPrm(.)                    │る Stack データ構造。
│  │├───────┤                                      │
│  ││inArg 4 of  StkCntxt_setCallPrm(.)                    │
│  │├───────┤                                      │
│  ││inArg 5 of  StkCntxt_setCallPrm(.)                    │
│    ├───────┤                                      │
│    │              │
│
│
│    void StkCntxt_setCallPrm(void(*pfAg)(const struct StStackAndContext**,...)
│           ,const struct StStackAndContext** cppStStackAndContextAg,... )
│
│    ├───────┤                                        
│    │              │                                        
│    ├───────┤                                        
│    │bp of PcCntxt_return2Task をここに移動する。== BPret2 ← これは setCallPrm で壊さない            
│    ├───────┤                                      ← これも setCallPrm で壊さない            
│    │PcCntxt_return2Task(.) への return address            │
│    ├───────┤                                      │
│  ●│← cppStStackAndContextAg of pfAg(.),StkCntxt_setCallPrm(.)
│    ├───────┤                                      │ここまでは task(.)
│  ││inDamieAt[0] in PcCntxt_executeLoopPolling(.)         │と同じスタック・フレーム
│  │├───────┤                                      │構造となる。
│  ││inDamieAt[1] in PcCntxt_executeLoopPolling(.)         │
│  │├───────┤                                      │PcCntxt_return2Task()
└→││inDamieAt[2] in PcCntxt_executeLoopPolling(.)         │を呼び出すことで作られ
    │├───────┤                                      │る Stack データ構造。
    ││inDamieAt[3] in PcCntxt_executeLoopPolling(.)         │
    │├───────┤                                      │
    ││inDamieAt[4] in PcCntxt_executeLoopPolling(.)         │
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │

下は PcCntxt_return2Task(.) に属するスタック・フレームの構造である

EBP-->0x0012ff34: 0x0012ff58 == EBP                  <-- ここに pfAg を置いて return を実行する
      0x0012ff38: 0x00401e63 == return address         
      0x0012ff3c: 0x00409168 == pStDelayAndContextAg <-- &pStStackAndContextAg はここを指している
      0x0012ff40: 0x???????? == inDamieAt[0] == 3    <-- arg1 を設定する
           ・         ・             ・
      0x0012ff50: 0x???????? == inDamieAt[4] == 0    <-- arg5 を設定する

       TyByte PcCntxt_return2Task(const struct StDelayPcContext* pStDelayPcContextAg)
        
      │              │
      ├───────┤
      │auto variable │
      ├───────┤
      │EBP           │
      ├───────┤                                        
      │PcCntxt_return2Task(.) 呼び出し側への return address    
      ├───────┤                                        
    ●│pStDelayPcContextAg of PcCntxt_return2Task(.) 
      ├───────┤                                      
      │inArg 1 of  StkCntxt_setCallPrm(.)                    │
      │───────┤                                      │
      │inArg 2 of  StkCntxt_setCallPrm(.)                    │StkCntxt_setCallPrm()
   y  ├───────┤                                      │を呼び出すことで作られ
      │inArg 3 of  StkCntxt_setCallPrm(.)                    │る Stack データ構造。
      ├───────┤                                      │
      │inArg 4 of  StkCntxt_setCallPrm(.)                    │
      ├───────┤                                      │
      │inArg 5 of  StkCntxt_setCallPrm(.)                    │
      ├───────┤                                      │
      │              │
    < -- chekAndExecute(.) の auto 変数領域を callTaskSub(.) の引数領域とみな
        せるように、データを変換する
    <-- DPC が入ったものを標準とする。連続ポーリングが必要ならば requestDPC
        を最後に加える
    <-- call(&pStStackAndCntxt, f,...) とする。
    <-- 共通サブルーチンが使えるように 領域を確保しない #define と関数宣言だけの
    <-- recursive like call を認めるためには専用の suspend が必要となる
        ヘッダが必要となる
    <-- ユーザーが確保したスタック範囲はユーザーが開放する
    <-- debugger で stPcContextStt, cstStDelayPcContextStt の値が固定されているらしい


retrunFromTaskSub(kc struct StStackAndContext**, int)

     dfCall(f, arg) を呼ぶ前のタスク・コンテキスト

 EAX = 0040C000 EBX = 7FFDF000 ECX = 00406F3C
 EDX = 00409218 ESI = 00000000 EDI = 00000000
 EIP = 00406F4A ESP = 0012FF2C EBP = 0012FF34
 EFL = 00000202 CS = 001B DS = 0023 ES = 0023
 SS = 0023 FS = 0038 GS = 0000 OV=0 UP=0 EI=1 PL=0
 ZR=0 AC=0 PE=0 CY=0

 ここのコンテキストに戻すように 0x12ff34 スタックより 4+8 小さい位置に戻りアドレスを積み、bp=0x12ff34 に設定して ret を実行する。
真ん中の 4 は ret 命令分の 4 byte である
二つ目の 8 は StkCntxtCall(.) の次に add sp,8 がある分の補正である


MS VC5.0 コンパイラでの割り込みタスク・コンテキス・スイッチ

IntCntxt_suspend(pStIntrCntxtAg) ←PcCntxt_suspend(.) を使うでの SP データ構造

      │              │
      ├───────┤
      │auto variable │← sp
      ├───────┤
      ├───────┤
      │auto variable │
      ├───────┤
      │EBP           │← bp
      ├───────┤                                        
      │InterruptTask(.) 呼び出し側への return address    
      ├───────┤                                        
    ●│pStDelayPcContextAg of PcCntxt_return2Task(.) 
      ├───────┤                                        
      │              │

        edi      <-- esp==0x12fd58
        esi
        ebx
        ebp      <-- ebp==0x12fd64
        return address
        pStIntrCntxtAg
                 <-- IntCntxt_suspend(.) を呼び出す前に SP が差していた

    add ebp, [ebp]
    mov esp, ebp
    pop ebp
    ret
  を IntCntxt_suspend(.) の最後で実行することで DfIntTask() からの戻りと
  同じ操作をする

VC::IntCntxt_suspend(pStIntrCntxtAg, pByDamieAg) での SP データ構造

        edi      <-- esp==0x12fd58
        esi
        ebx
        ebp      <-- ebp==0x12fd64
        return address
        pStIntrCntxtAg
        pByDamieAg
                 <-- IntCntxt_suspend(.) を呼び出す前に SP が差していた

    add esp,8
    mov esp, ebp
    pop ebp
    ret
  を IntCntxt_suspend(.) の最後で実行することで DfIntTask() からの戻りと
  同じ操作をする
MS VC5.0/6.0 コンパイラでの割り込みタスク・サブルーチン
スタック・フレーム、戻りアドレス

void StkCntxt_setCall0(void(*pfAg)(const struct StStackAndContext*
        ,const struct StStackAndContext** cppStDelayPcContextAg )

      │              │
      ├───────┤       
      │auto variable │← sp  │
      ├───────┤       │pfAg stack frame
      ├───────┤       │
      │auto variable │       │
      ├───────┤       │
      │EBP           │← bp  │(cppStDelayPcContextAg)-2
      ├───────┤                                        
      │InterruptTask(.) 呼び出し側への return address    
      ├───────┤                                        
    ●│cppStDelayPcContextAg of PcCntxt_return2Task(.) 
      ├───────┤                                        
      │inDamie:arg   │
      ├───────┤
      │              │
TyWord StkCntxt_call( struct StStackAndContext** cppStAg)

      │ret address   │== 0x40707f
      ├───────┤       
      │cppStAg:12ff20│
      ├───────┤       
      │chAt          │← sp                                   0x12ff10
      ├───────┤       │
      │inAt        e │       │
      ├───────┤       │
      │EBP           │← bp  │(cppStDelayPcContextAg)-2
      ├───────┤                                        
      │InterruptTask(.) 呼び出し側への return address    
      ├───────┤                                        
    ●│cppStDelayPcContextAg of PcCntxt_return2Task(.) ←      0x12ff20
      ├───────┤                                        
      │inDamie:arg   │
      ├───────┤
      │              │
void StkCntxt_returnFromTaskSub( struct StStackAndContext** cppStAg)

      │              │
      ├───────┤       
      │auto variable │← sp  │
      ├───────┤       │pfAg stack frame
      ├───────┤       │
      │auto variable │       │
      ├───────┤       │
      │EBP           │← bp  │(cppStDelayPcContextAg)-2
      ├───────┤                                        
      │InterruptTask(.) 呼び出し側への return address    
      ├───────┤                                        
    ●│cppStDelayPcContextAg of PcCntxt_return2Task(.) 
      ├───────┤                                        
      │inDamie:arg   │
      ├───────┤
      │              │


78K4 コンテキス・スイッチ

mm model defalut 最適化条件でのコンテキスト・スイッチである。最適化やメモリ・モデルを変えると、スタックへのオート変数の積み方が変わる。それに伴いコンテキスト制御も変わってくる。

78K4 の C コンパイラでは、オート変数へのアクセスを [sp+n] で行う。x86 での ebp が存在しない。そのためスタック・フレームを &pVdPrmAg - &pStDelayPcContextAg で作る。dfSetStackFrame(pVdPrmAg) をタスクの最初に実行する。dfTask(.) マクロに含めることも可能だが、関数を開始する'{' が一つ隠れてしまう。これを使っているスクリプトもある。関数を開始する '{' を残すほうを優先して、明示的にユーザが dfSetStackFrame(.) を書く。

x86 コンパイラでは dfSetStackFrame(pVdPrmAg) を空文にする。

78K4 関数スタック
_PcCntxt_checkAndExecute:

78K4
タスクの開始、dfFunction(taskSample.)、 dfCall(taskSample) を実行してタスク関数に移って
直後、まだタスクのスタックフレームを作る前のスタックの様子

      ├───────┤←───────────→ taskSample(StTcb stTcbAg__, pVdPrm)
      │return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
      ├───────┤
      │pVdPrmAt      │ uup==pVdDamiAt, scheduler 側の auto 変数
      ├───────┤
      │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
      ├───────┤
      │ rp3          │PcCntxt_checkAndExecute(.) が rp3 を保存しない。どこかで
      ├───────┤壊れるかもしれないのでスタックにのせる
      │              │


auto 変数の数によってコンパイラがスタック・フレームを作り上げ下のように配置する


    ●│pStTcbAg__  push whl でスタックにつむ: 3 byte
   O↑├───────┤                            up=ax:pStDelayPcContextAg
   F││auto variable │                            whl == 
   F││   of task    │                          
   S││              │                          
   E││              │                           
   T││              │                          
    │├───────┤←───────────→ taskSample(StTcb stTcbAg__, pVdPrm)
    ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
    │├───────┤
    ↓│pVdPrmAt      │ uup==pVdDamiAt, scheduler 側の auto 変数
      ├───────┤
      │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
      ├───────┤
      │ rp3          │PcCntxt_checkAndExecute(.) が rp3 を保存しない。どこかで
      ├───────┤壊れるかもしれないのでスタックにのせる
      │              │

      mm medium
      │              │
      ├───────┤
      │   up         │← sp, uup:pVdDamieAt, ax==pStDelayPcContextAg 
      ├───────┤
    ●│   vp         │   :pStStateDelayAt
    │├───────┤
    ││   rp3        │   :inReturnValueAt
    │├───────┤
    ││return address│  of return2Task() and m_pTimeUpAddress(),
    │├───────┤  whl = pStDelayPcContextAg
    ││    vp        │← sp, uup:pVdDamieAt == pStDelayPcContextAg
      ├───────┤   vvp = pStDelayPcContextAg->m_pVdPrm
      │    up:       │   ==pStDelayPcContextAg
      ├───────┤
      │return address│ and whl = pStDelayPcContextAg of _PcCntxt_checkAndExecute()
      ├───────┤
      │pVdDamiAt     │ scheduler 側の auto 変数
      ├───────┤
      │   ・         │
      ├───────┤
      │arg n         │

          mm medium
          │              │
          ├───────┤
  0xdfdd●│   ax         │←sp :pStDelayPcContextAg
        │├───────┤
        ││   rp3        │   :inReturnValueAt
        │├───────┤
  0xdfe1││return address│  of return2Task() and m_pTimeUpAddress(),
        ││              │
        │├───────┤   ax = pStDelayPcContextAg
        ││    vp        │vvp = pStDelayPcContextAg->m_pVdPrm a← m_enState
          ├───────┤   
          │    up:       │uup:pVdDamieAt == pStDelayPcContextAg
          ├───────┤
    0xdfe8│    vp        │← sp
          ├───────┤
          │    up:       │
          ├───────┤
          │return address│ and whl = pStDelayPcContextAg of _PcCntxt_checkAndExecute()
          ├───────┤
          │pVdDamiAt     │ scheduler 側の auto 変数
          ├───────┤
          │   ・         │
          ├───────┤
          │arg n         │

		ml large
      │              │
      ├───────┤
      │   vvp        │← sp, uup:pVdDamieAt == pStDelayPcContextAg
      ├───────┤
      │   uup        │aut variable of task
      ├───────┤
      │return address│  of return2Task() and m_pTimeUpAddress(),
      ├───────┤  whl = pStDelayPcContextAg
      │   vvp        │← sp, uup:pVdDamieAt == pStDelayPcContextAg
      ├───────┤   vvp = pStDelayPcContextAg->m_pVdPrm
      │   uup        │
      ├───────┤
      │return address│ and whl = pStDelayPcContextAg of _PcCntxt_checkAndExecute()
      ├───────┤
      │pVdDamiAt     │ scheduler 側の auto 変数
      ├───────┤
      │   ・         │
      ├───────┤
      │arg n         │

static dfTaskFnc(task, pVdPrmAg) と PcCntxt_suspend(&pStDelayPcContextAg)
      mm medium memory model
      │              │
      ├───────┤
      │&pStDelayPcContextAg  push ax でスタックにつむ:2 byte ← sp
      ├───────┤
      │return address│  of PcCntxt_suspend(.):3 byte
      ├───────┤
      │pStDelayPcContextAg  push whl でスタックにつむ: 3 byte
   O↑│───────┤
   F││auto          │
   F││   viriable   │
   S│├───────┤
   E││return address│ and whl = pStDelayPcContextAg of task()
   T↓├───────┤
      │pVdPrmAt      │ == pVdDamiAtscheduler 側の auto 変数
      ├───────┤
      │   ・         │
      ├───────┤
      │arg n         │
      ml large memory model

      │              │
      ├───────┤
      │&pStDelayPcContextAg  push whl でスタックにつむ:3 byte ← sp
      ├───────┤
      │return address│  of PcCntxt_suspend(.):3 byte
      ├───────┤
      │pStDelayPcContextAg  push whl でスタックにつむ: 3 byte
   O↑│───────┤
   F││auto          │
   F││   viriable   │
   S│├───────┤
   E││return address│ and whl = pStDelayPcContextAg of task()
   T↓├───────┤
      │pVdPrmAt      │ == pVdDamiAtscheduler 側の auto 変数
      ├───────┤
      │   ・         │
      ├───────┤
      │arg n         │

return2Task(.) at PcCntxt.c
return2Task(.) のアッセンブラ部分は PcCntxt.c と IntCntxt.c を同じにできない。使うオート変数の数がことなるので、オフセット補正が異なるからだ。戻り値を return2Task(.)::PcCntxt.c が使う点でも、異なる。
static void return2Task( struct StPcContext* pStPcContextAstruct)
  at PcCntxt.c and PcCntxt_exeuteLoopPolling()

          mm medium
          │              │
          ├───────┤
  0xdfdd  │   up         │←sp up:pStDelayPcContextAg
          ├───────┤
  0xdfdf●│   vp         │   vp:pStDelayAt
        │├───────┤
        ││   rp3        │   rp3:inReturnValueAt
        │├───────┤
  0xdfe3││return address│  of return2Task() and m_pTimeUpAddress(),
        ││              │
        │├───────┤
    0xdfe6│    hl:00     │← sp pVdDamiAt
          ├───────┤
          │    ax:       │stStateDelayAt
          ├───────┤
          │    up:       │
          ├───────┤
    0xdfec│return address│ and ax = pStDelayPcContextAg of PcCntxt_exeuteLoopPolling()
          │  0xc643      │ 
          ├───────┤
          │arg n         │

static void return2Task( struct StDelayPcContext* pStDelayPcContextAg)
 at PcCntxt.c
      │              │
      ├───────┤
      │pStDelayPcContextAg  push whl でスタックにつむ: 3 byte
   O↑├───────┤        ├───────┤  uup=whl:pStDelayPcContextAg
   F││auto          │of task │push register │  vvp==pStStateDelayAt
   F││   viriable   │        │   up         │ :pStDelayPcContextAg
   S││              │        │   vp         │ :pStStateDelayAt
   E││              │        │   rp3        │ :inReturnValueAt
   T│├───────┤        ├───────┤
    ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
    ↓├───────┤
      │pVdPrmAt      │ uup==pVdDamiAt, scheduler 側の auto 変数
      ├───────┤
      │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
      ├───────┤
      │ rp3          │PcCntxt_checkAndExecute(.) が rp3 を保存しない。どこかで
      ├───────┤壊れるかもしれないのでスタックにのせる
      │              │

int PcCntxt_call( struct StDelayPcContext** ppStAg)
PcDfcOOP.h::dfFunction(pfAg,pVdPrmAg)
SkIntOOP.h::dfCall( pfAg, pVdPrmAg__)
SkDfcOOP.h::dfCall( pfAg, pVdPrmAg__),dfFunction(pfAg,pVdPrmAg)
でスケジューラーのスタック・フレームと、タスクのスタックフレームを重ねあわせる
      ppStAg が ● を指している。ppStAg->m_inStackFram だけ先に pVdPrmAg がある。
      その直前に戻りアドレスが存在している。
      
      すでに ppStAg->m_inStackFram の設定は dfSetStackFrame(pVdPrmAg) で終わっている

      mm medium memory model

      │              │
      ├───────┤
      │return address│ of PcCntxt_call
      ├───────┤
    ●│pStDelayPcContextAg  push whl でスタックにつむ: 3 byte
   O↑├───────┤                            up=ax:pStDelayPcContextAg
   F││auto variable │                            whl == 
   F││   of task    │                          
   S││              │                          
   E││              │                           
   T│├───────┤                          
    ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
    ↓├───────┤
      │pVdPrmAt      │ uup==pVdDamiAt, scheduler 側の auto 変数
      ├───────┤
      │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
      ├───────┤
      │ rp3          │PcCntxt_checkAndExecute(.) が rp3 を保存しない。どこかで
      ├───────┤壊れるかもしれないのでスタックにのせる
      │              │
      ml large memory model
      
      ppStAg が ● を指している。ppStAg->m_inStackFram だけ先に pVdPrmAg がある。
      その直前に戻りアドレスが存在している。
      
      すでに ppStAg->m_inStackFram の設定は dfSetStackFrame(pVdPrmAg) で終わっている

      │              │
      ├───────┤
      │return address│ of PcCntxt_call
      ├───────┤
    ●│pStDelayPcContextAg  push whl でスタックにつむ: 3 byte
   O↑├───────┤                            uup=whl:pStDelayPcContextAg
   F││auto variable │                            vvp==pStStateDelayAt
   F││   of task    │                          
   S││              │                          
   E││              │                           
   T│├───────┤                          
    ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
    ↓├───────┤
      │pVdPrmAt      │ uup==pVdDamiAt, scheduler 側の auto 変数
      ├───────┤
      │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
      ├───────┤
      │ rp3          │PcCntxt_checkAndExecute(.) が rp3 を保存しない。どこかで
      ├───────┤壊れるかもしれないのでスタックにのせる
      │              │

void StkCntxt_setCallPrm(struct StStackAndContext** ppStStackAndContextAg
,int(*pfAg)(struct StStackAndContext*, void*), void* pVdAg )

      mm memory model のとき

      ppStStackAndContextAg が ● を指している。ppStAg->m_inStackFram
      だけ先に pVdPrmAg がある。その直前に戻りアドレスが存在している。

      uup == ppStIntStackCntxtVdPrmAg である

      │    up        │← sp uup=ppStStackAndContextAg, rp3:pStTaskStackContextDataAt
      ├───────┤
      │    vp        │
      ├───────┤
      │    rp3       │
      ├───────┤
      │return address│ of SkIntCnt_setCallPrm(.)
      ├───────┤
      │ pfAg         │
      ├───────┤
      │ pVdPrmAg     │← [sp+12]
      ├───────┤
m  O●│ ax:pStPcContextAg__  push  でスタックにつむ: 3 byte
_  F↑├───────┤                            uup=whl:pStDelayPcContextAg
i  F││ up           │
n  S│├───────┤                            
S  E││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
t  T↓├───────┤
a     │pVdPrmAt      │ uup==pVdDamiAt, scheduler 側の auto 変数
c     ├───────┤
k     │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
F     ├───────┤
r     │              │
a      
m   
e
      ppStStackAndContextAg が ● を指している。ppStAg->m_inStackFram
      だけ先に pVdPrmAg がある。その直前に戻りアドレスが存在している。

      uup == ppStStackAndContextAg である

      │              │
      ├───────┤
      │    vvp       │← sp uup=ppStStackAndContextAg
      ├───────┤
      │    uup       │
      ├───────┤
      │return address│ of StkCntxt_setCallPrm(.)
      ├───────┤
      │ pfAg         │
      ├───────┤
      │ pVdAg        │
      ├───────┤
    ●│pStDelayPcContextAg  push whl でスタックにつむ: 3 byte
m  O↑├───────┤                            uup=whl:pStDelayPcContextAg
_  F││auto variable │                            vvp==pStStateDelayAt
i  F││   of task    │                          
n  S││              │                          
S  E││              │                           
t  T│├───────┤                          
a   ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
k   ↓├───────┤
F     │pVdPrmAt      │ uup==pVdDamiAt, scheduler 側の auto 変数
r     ├───────┤
a     │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
m     ├───────┤
e     │              │
タスク・スタック・データ
      │              │
      ├───────┤
      │m_pVdPrm      │
      ├───────┤
    ││m_pfTimeup    │3 byte ← m_pInStack │m_stPcContext│5 byte
    │├───────┤                     │m_stPcContext│
    ││m_inStackFrame│2 byte               │m_stPcContext│
    │├───────┤
    ││m_pVdPrm      │3 byte
      ├───────┤
    ││m_pfTimeup    │
    │├───────┤

struct StStackAndContext{
    struct StPcContext  m_stPcContext;  /* 5byte: m_pfTimeup  m_inStackFrame*/
    void*               m_pVdPrm;
    struct StStateDelay m_stStateDelay;
    /* m_stPcContext, m_stStateDelay, m_pVdPrm までは StDelayPcContext と同じ*/
    int*                m_pInStack;
}
setCallPrm(.) での 11 offset
static dfTaskFnc(test,pVdPrmAg)
{
    dfSetStackFrame(pVdPrmAg);
    dfCall(test,9);
}

をコンパイルすると、下のコードを吐き出す。

; line   629 : static dfTaskFnc(test,pVdPrmAg)
; line   630 : {
_test:
$DGL    1,411
    push    whl
??bf_test:
; line   631 :     dfSetStackFrame(pVdPrmAg);
$DGL    0,2
    movg    whl,[sp+6]  ; pVdPrmAg
    call    !!_dfSetStackFrame
; line   632 :     dfCall(test,9);
$DGL    0,3
    movg    whl,#09H    ; 9
    push    whl
    movg    whl,#_test
    push    whl
    movg    whl,sp
    addg    whl,#06H
    call    !!_StkCntxt_setCallPrm
    addwg   sp,#06H ; 6             ;  5 byte 命令 addg rg,#
    movg    whl,sp                  ;  2 byte 命令 movg rg,rg
    call    !!_PcCntxt_call         ;  4 byte 命令 call !!
; line   633 : }
$DGL    0,4
??ef_test:
    pop whl
    ret
??ee_test:
     (*ppStStackAndContextAg)->m_pVdPrm = *(void**)(ppStStackAndContextAg + 1);
の式を使っても 78K4 では TCB に pVdDamiAt in scheduler を保存できない
StkCntxt_returnFromTaskSub(.)
void StkCntxt_returnFromTaskSub( struct StStackAndContext** ppStAg)

既に StkCntxt_setReturnValue(.) により pVdDamieAt に戻り値が仮値として設定されている。StkCntxt_returnFromTaskSub(.) は タスク・スタック上 pVdDamieAt を戻り値として bc register に入れる。の m_pVdPrm の値をスケジューラーの pVdDamieAt を入れる

インライン・アッセンブラ・コードに入ったとき vvp には m_pInStack の値が入っている。tde には StStackAndContext** ppStAg の (*ppStAg) が入っている。

サブルーチン側のスタック・フレームから pVdDamieAt 位置を計算し、タスク・スタックにある m_inStackFrmae 値より、戻る側の ● &pStStackAndContextAg を計算する
       mm  medium memory model 

      │              │
      ├───────┤
      │    up        │← sp uup=ppStStackAndContextAg ( ppStAg )
      ├───────┤      vvp: pStPcContextAt = (*ppStStackAndContextAg)->m_inStack+8
      │    vp        │      tde: *ppStStackAndContextAg (*ppStAg)
      ├───────┤
      │return address│ of StkCntxt_returnFromTaskSub(.)
      ├───────┤
    ●│pStStackAndContextAg  push ax でスタックにつむ: 2 byte
   O│├───────┤                            uup=whl:pStDelayPcContextAg
   F││auto variable │                            vvp==pStStateDelayAt
● F││   of task    │                          
↑ S││              │                          
│ E││              │                           
│ T│├───────┤                          
│  ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
│  ↓├───────┤
      │pVdDamieAt    │ uup==pVdDamiAt, scheduler 側の auto 変数
      ├───────┤
      │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
      ├───────┤
      │              │

struct StStackAndContext{
    struct StPcContext  m_stPcContext;  /* 5byte: m_pfTimeup  m_inStackFrame*/
    void*               m_pVdPrm;
    struct StStateDelay m_stStateDelay;
    /* m_stPcContext, m_stStateDelay, m_pVdPrm までは StDelayPcContext と同じ*/
    int*                m_pInStack;

       ml  large memory model 

      │              │
      ├───────┤
      │    vvp       │← sp uup=ppStStackAndContextAg
      ├───────┤      vvp = (*ppStStackAndContextAg)->m_inStack+8
      │    uup       │      tde = *ppStStackAndContextAg
      ├───────┤
      │return address│ of StkCntxt_returnFromTaskSub(.)
      ├───────┤
    ●│pStDelayPcContextAg  push whl でスタックにつむ: 3 byte
   O│├───────┤                            uup=whl:pStDelayPcContextAg
   F││auto variable │                            vvp==pStStateDelayAt
● F││   of task    │                          
↑ S││              │                          
│ E││              │                           
│ T│├───────┤                          
│  ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
│  ↓├───────┤
      │pVdDamieAt    │ uup==pVdDamiAt, scheduler 側の auto 変数
      ├───────┤
      │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
      ├───────┤
      │              │

struct StStackAndContext{
    struct StPcContext  m_stPcContext;  /* 5byte: m_pfTimeup  m_inStackFrame*/
    void*               m_pVdPrm;
    struct StStateDelay m_stStateDelay;
    /* m_stPcContext, m_stStateDelay, m_pVdPrm までは StDelayPcContext と同じ*/
    int*                m_pInStack;




IntCntxt_restartImmediately(.) でのスタック変化
      mm memory model のとき
      dfStartIntStt(task,0) ---- dfWaitInt()

          ├───────┤
    0xe0e6│&pStPcContextAg:0xebeb
          ├───────┤
    0xe0e8│return address│PcCntxt_suspend
          │     0xe0015b │
          ├───────┤
  │0xe0eb│pStPcContextAg│
  │      ├───────┤
5 │0xe0ed│return address│task(.) of remocon.c
  │      │     0xb0c6ce │
  │      ├───────┤
  │0xeof0│  00 pVdAg of (*pfAg)(pStAg,pVdAg)  and AX = 0xe100:&stPcContextStt
          ├───────┤IntCntxt_startImmediately(pStPcContextStt, 0) が (*pf)(.) と呼び出す
          │  up:rp5      │
          ├───────┤
    0xe0f4│  vp:rp4      │

      mm memory model のとき
      IntCntxt_restartImmediately((pStPcContesxtAg,pVdRestartAg) 
      -- restart2Task(pStPcContesxtAg) ---- dfWaitInt()

          ├───────┤
    0xe0e6│&pStPcContextAg:0xebeb
          ├───────┤
    0xe0e8│return address│PcCntxt_suspend
          │     0xe0015b │
          ├───────┤
  │0xe0e9│pStPcContextAg│==0xe100
  │      ├───────┤
5 │0xe0eb│return address│task(.) of remocon.c
  │      │     0xb0c6ce │
  │      ├───────┤
  │0xeoee│  01 pVdAg of IntCntxt_restartImmediately(pStPcContextAg, pVdRestartAg)
          ├───────┤
    0xe0f0│  up:rp5      │
          ├───────┤
    0xe0fe│  vp:rp4      │
          ├───────┤
          │              │

      ml memory model のとき

      ppStStackAndContextAg が ● を指している。ppStAg->m_inStackFram
      だけ先に pVdPrmAg がある。その直前に戻りアドレスが存在している。

      uup == ppStStackAndContextAg である

      │              │
      ├───────┤
      │    vvp       │← sp uup=ppStStackAndContextAg
      ├───────┤
      │    uup       │
      ├───────┤
      │return address│ of StkCntxt_setCallPrm(.)
      ├───────┤
      │ pfAg         │
      ├───────┤
      │ pVdAg        │
      ├───────┤
    ●│pStDelayPcContextAg  push whl でスタックにつむ: 3 byte
m  O↑├───────┤                            uup=whl:pStDelayPcContextAg
_  F││auto variable │                            vvp==pStStateDelayAt
i  F││   of task    │                          
n  S││              │                          
S  E││              │                           
t  T│├───────┤                          
a   ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
k   ↓├───────┤
F     │pVdPrmAt      │ uup==pVdDamiAt, scheduler 側の auto 変数
r     ├───────┤
a     │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
m     ├───────┤
e     │              │


SkIntCnt_setCallPrm(.) での 11 offset
static void return2Task( struct StDelayPcContext* pStDelayPcContextAg) at IntCntxt.c

m_stStateDelay への設定と return value の設定がないことを除いて return2Task(.) at PcCntxt.c と同じである。



void SkIntCnt_setCallPrm(struct StIntStackCntxtVdPrm** ppStIntStackCntxtVdPrmAg
,int(*pfAg)(struct StIntStackCntxtVdPrm*, void*), void* pVdAg )

割り込みではない StkCntxt_setCallPrm(.) とは
  1. StTaskStackContextData ←→ StIntCntxtVdPrmDamie
  2. StStackAndContext ←→ StIntStackCntxtVdPrm
と、TCB が異なっている。それ以外は同じである。アッセンブラ部分は全く同じである
      mm memory model のとき

      ppStStackAndContextAg が ● を指している。ppStAg->m_inStackFram
      だけ先に pVdPrmAg がある。その直前に戻りアドレスが存在している。

      uup == ppStIntStackCntxtVdPrmAg である

      │    up        │← sp uup=ppStIntStackCntxtVdPrmAg, rp3:pStIntCntxtVdPrmDamieAt
      ├───────┤
      │    vp        │
      ├───────┤
      │    rp3       │
      ├───────┤
      │return address│ of SkIntCnt_setCallPrm(.)
      ├───────┤
      │ pfAg         │
      ├───────┤
      │ pVdPrmAg     │← [sp+12]
      ├───────┤
m  O●│ ax:pStPcContextAg__  push  でスタックにつむ: 3 byte
_  F↑├───────┤                            uup=whl:pStDelayPcContextAg
i  F││ up           │
n  S│├───────┤                            
S  E││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
t  T↓├───────┤
a     │pVdPrmAt      │ uup==pVdDamiAt, scheduler 側の auto 変数
c     ├───────┤
k     │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
F     ├───────┤
r     │              │
a      
m   
e

SkIntCnt _returnFromTaskSub(.) についても、TCB データ構造が異なる以外は StkCntxt_returnFromTaskSub(.) と同じである
void SkIntCnt_returnFromTaskSub( struct StIntStackCntxtVdPrm** ppStAg)

           mm medium, default option 

          │              │
          ├───────┤
    0xdfe2│    up        │← sp up=ppStAg ( ppStAg )
          ├───────┤      vvp: pStPcContextAt = (*ppStStackAndContextAg)->m_inStack+7
          │    vp        │      tde: *ppStStackAndContextAg (*ppStAg)
          ├───────┤
    0xdfe6│return address│ of StkCntxt_returnFromTaskSub(.)
          │              │
          ├───────┤
  0xdfe9●│pStStackAndContextAg  push ax でスタックにつむ: 2 byte
       O│├───────┤                            uup=whl:pStDelayPcContextAg
       F││auto variable │                            vvp==pStStateDelayAt
    ● F││   of task    │                          
    ↑ S││              │                          
    │ E││              │                           
    │ T│├───────┤                          
    │  ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
    │  ↓├───────┤
┌─0xdfee│pVdDamieAt    │ uup==pVdDamiAt, scheduler 側の auto 変数
│        ├───────┤
│        │uup:pStDelayPcContextAg of PcCntxt_checkAndExecute(.) アッセンブラで積む
│        ├───────┤
│        │              │
│
│スタック上に残してあった戻った側のスタック・フレーム値で、スタック・フレームを再構築する
│
│        ├───────┤
│  0xdfe6│return address│
│        │              │                           
│        ├───────┤
│0xdfe9●│pStStackAndContextAg  push ax でスタックにつむ: 2 byte
│     O│├───────┤                            uup=whl:pStDelayPcContextAg
│     F││auto variable │                            vvp==pStStateDelayAt
│  ● F││   of task    │                          
│  ↑ S││              │                          
│  │ E││              │                           
│  │ T│├───────┤                          
│  │  ││return address│ and whl = pStDelayPcContextAg of,return2Task(), task()
│  │  ││              │                           
│  │  ↓├───────┤
└→0xdfee│pVdDamieAt    │ uup==pVdDamiAt, scheduler 側の auto 変数
          ├───────┤



dfCallInt(.) がタスク・スタックに保存する再開アドレスは 0x036e
          mm medium memory model and default optiomaization

          ├───────┤up = ppStIntStackCntxtVdPrmAg
    0xdfd8│ up:          │← sp up,vp は SkIntCnt_setCallPrm() の woking arear
          ├───────┤
          │ vp:          │
          ├───────┤
          │ rp3          │
          ├───────┤                             │
    0xdfde│return address│of SkIntCnt_setCallPrm(.)    │
    0xe151│  :0x0362     │                             │
          ├───────┤                             ├──────────
          │detectBusFree() function address       0xe154│&pStPcContextAg__:0xe159
          │  :0x2a1      │                             ├─────────
          ├───────┤                       0xe156│return address   :0x00031c
          │ pVdAg:0x0000 │                             │of PcCntxt_suspend()
┌────├───────┤                             ├─────────
│●0xdfe6│ ax:pStPcContextAg__ ← sp             0xe159│ax:pStPcContextAg__:0xe10e
│  0xe159├───────┤    of makeFreeBusState(.)   ├─────
│  0xdfe8│return address│of makeBusFreeState(.)       │
│  0xe15b│   0x0c6a2:0xb7a3   │                       │
│        ├───────┤                            
│  0xdfeb│ pVdPrmAg     │ of IntCntxt_startImmediately() 
│  0xe15e├───────┤
│        │ up:          │up,vp は IntCntxt_startImmediately() の woking arear
│        ├───────┤
│        │ vp:          │
│        ├───────┤
│  0xdff1│return address│of IntCntxt_startImmediately(.)
│  0xe164│   0x00785    │
│        ├───────┤                            
│  0xe167│makeBusFreeState()
│        │  :0x32e      │
│        ├───────┤
│  0xe16a│pVdAg:0x0000  │
│        ├───────┤
│
│
│            0xdfe0 から 0xdfe2 に timeup address を代入して、そっちに ret 命令を使って移る
│        ├───────┤up = ppStIntStackCntxtVdPrmAg
│  0xdfe1│ up:          │← sp. up は PcCntxt_call() の woking arear
│  0xe154├───────┤
│  0xdfe3│return address│of PcCntxt_call(.)
│  0xe156│  :0x0362     │
│        ├───────┤
│●0xdfe6│ ax:pStPcContextAg__ ← sp
    0xe159├───────┤    of makeFreeBusState(.)




          ├───────┤up = ppStIntStackCntxtVdPrmAg
    0xdfd8│ up:          │← sp up,vp は SkIntCnt_setCallPrm() の woking arear
          ├───────┤
          │ vp:          │
          ├───────┤
          │ rp3          │
          ├───────┤
    0xdfde│return address│of SkIntCnt_setCallPrm(.)
          │  :0x0362     │
          ├───────┤
          │detectBusFree() function address
          │  :0x2a1      │
          ├───────┤                            
          │ pVdAg:0x0000 │
┌────├───────┤
│●0xdfe6│ ax:pStPcContextAg__ ← sp
│        ├───────┤    of makeFreeBusState(.)
│  0xdfe8│return address│of makeBusFreeState(.)
│        │   0x0c6a2    │
│        ├───────┤                            
│  0xdfeb│ pVdPrmAg     │ of IntCntxt_startImmediately() 
│        ├───────┤
│        │ up:          │up,vp は IntCntxt_startImmediately() の woking arear
│        ├───────┤
│        │ vp:          │
│        ├───────┤
│  0xdff1│return address│of IntCntxt_startImmediately(.)
│        │   0x00785    │
│        ├───────┤                            
│        │makeBusFreeState()
│        │  :0x32e      │
│        ├───────┤
│        │pVdAg:0x0000  │
│        ├───────┤
│
│
│            0xdfe0 から 0xdfe2 に timeup address を代入して、そっちに ret 命令を使って移る
│        ├───────┤up = ppStIntStackCntxtVdPrmAg
│  0xdfe1│ up:          │← sp. up は PcCntxt_call() の woking arear
│        ├───────┤
│  0xdfe3│return address│of PcCntxt_call(.)
│        │  :0x0362     │
│        ├───────┤
│●0xdfe6│ ax:pStPcContextAg__ ← sp
          ├───────┤    of makeFreeBusState(.)

return2Task(.) at IntCntxt.c
dfWaintInt(.) も PcCntxt_suspend(.) を使っている。PcCntxt_suspend(.) は int の戻り値をもつ。しかし割り込みルーチン内のタスクにはタイム・アップがない。タスク状態がない。PcCntxt_suspend(.) の戻り値は 1 に固定した。
static void return2Task( struct StPcContext* pStPcContextAstruct)
  at IntCntxt.c
      │              │
      ├───────┤
      │pStDelayPcContextAg  push whl でスタックにつむ: 3 byte
   O↑├───────┤        
   F││auto          │of task 
   F││   viriable   │        ├───────┤uup←pStDelayPcContextAg
   E││              │        │   up         │
   T│├───────┤        ├───────┤
0xdfeb│return address│ and ax = pStDelayPcContextAg of return2Task(){..}
      │  0x0c6d7     │
    ↓├───────┤
0xdfee│ pVdPrmAg:2   │
      ├───────┤
      │ up:          │ working of IntCntxt_restartImmediately()
      ├───────┤
      │ vp           │
      ├───────┤
0xdff4│return address│of IntCntxt_restartImmediately()
      │   0x42ca     │
      ├───────┤
      │              │
      │              │

setjmp(.)/longjmp(.)
    rp3, RG4, RG5, RG7(PC), SP: 14 byte


78K0 コンテキス・スイッチ

78K0 関数スタック
    関数の最初と最後
    _CntxtGrp_checkAndExecute:
    $DGL    1,43
        push    hl
        push    ax
        movw    ax,sp
        movw    hl,ax
    ??bf_CntxtGrp_checkAndExecute:
    ; line     9 :     /* Round Robin 制御とする。そのための 1 word は安い */
    ; line    10 :     static const struct StGroupVTable* cpStStt;
    ; line    11 : 
    ; line    12 :     for ( cpStStt = cpStGroupVTableOrgnStt; cpStStt != 0
    $DGL    0,5
        movw    ax,!_cpStGroupVTableOrgnStt
        movw    !?L0003,ax  ; cpStStt
    ?L0004:
        movw    ax,!?L0003  ; cpStStt
        or  a,x
        bz  $?L0005

            ・
            ・
            ・
            ・

        movw    ax,!_cpStGroupVTableOrgnStt
        movw    !?L0003,ax  ; cpStStt
    ; line    33 : }
    $DGL    0,26
    ??ef_CntxtGrp_checkAndExecute:
        pop ax
        pop hl
        ret

      │auto var      │ ←----- sp, and hl
      ├───────┤    ↑
      │   ・         │    │
      ├───────┤    │
      │auto var      │    │この差分をコンテキストに溜める。
      ├───────┤    │
      │arg 1 in ax   │ ←--------- pStDelayAndContext 引数
      ├───────┤    ↓
      │hl            │ --------
      ├───────┤
      │return address│
      ├───────┤
      │arg 2         │
      ├───────┤
      │   ・         │
      ├───────┤
      │arg n         │

  1. sp と hl の差分は 0 になっている。PcCntxt に溜めるのは、古い hlを入れてあるスタック位置と現在のスタック位置の差分である。
  2. RTOS がタスクにコンテキスト・スイッチを切りかえる時は、pStDelayAndContext 引数をスタックに設定し、sp を溜めておいたスタック位置の差分だけずらしてから、プログラム・カウンタをコンテキストに溜めてあった値にする。
  3. 関数の内容が極端に単純なとき、呼び出し側の hl や arg1 引数 ax をスタックに入れないことがある。しかしタスク関数では delay(.), suspend(.), terminate(.) などの関数が arg1 pStDelayAndContext を使う。こめためスタックに呼び出し側の hl や arg1 引数 ax を溜めることが保証される。


PcCntxt_suspend(.) stack データ構造
      │              │
      ├───────┤
      │pStPcContextAt;←-- hl at PcCntxt_suspend(.)
      ├───────┤
      │pStStateDelayAt;
      ├───────┤
┌──┤ppStDelayPcContextAg
│    ├───────┤ 
│┌─┤hl            │
││  ├───────┤
││  │task から PcCntxt_suspend(.) を読んだ時の return address
││  ├───────┤
│└→│task auto varN│-------
│    ├───────┤    ↑この差分を PcCntxt TCB に保存する
│    │   ・         │    │== ppStDelayPcContextAg - hl - 6*2
│    ├───────┤    │6 は pStPcContextAt, pStStateDelayAt, 
│    │task auto var1│    │     ppStDelayPcContextAg, hl, ret addr,
│    ├───────┤    │     pStDelayPcContextAg
└─→│pStDelayPcContextAg │
      ├───────┤    ↓
      │hl of PcCntxt_return2Task(.)←-- task(StDelayPcContext* )
      ├───────┤
      │PcCntxt_return2Task(.) への return address
      ├───────┤
      │inDamieAt[0] in PcCntxt_executeLoopPolling(.)
      ├───────┤
      │inDamieAt[1] in PcCntxt_executeLoopPolling(.)
      ├───────┤
      │inDamieAt[2] in PcCntxt_executeLoopPolling(.)
      ├───────┤
      │inDamieAt[3] in PcCntxt_executeLoopPolling(.)
      ├───────┤
      │inDamieAt[4] in PcCntxt_executeLoopPolling(.)
      ├───────┤
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)
      ├───────┤
      │return address│
      ├───────┤
      │              │


PcCntxt_return2Task(.) stack データ構造
      │              │←-- m_pTimeUpAddress を入れる。
      ├───────┤        sp をこの位置に設定する ret でタスク側に  context switch
      │              │ ←┐ hl = hl(of PcCntxt_return2Task)
      ├───────┤   │            - pStPcContextAt-> m_sp_hl
      │   ・         │   │
      ├───────┤   │
      │byReturnValueAt (at│[hl+1])←-- sp, hl                 
      ├───────┤   │                                   
      │pStPcContextAt│   │                                   
      ├───────┤   │                                   
      │pStStateDelayAt    │                                   
      ├───────┤   │                                   
    ●│pStDelayPcContextAg│of PcCntxt_return2Task(.) HLref2 │ここまでは task(.)
      ├───────┤   ↓                                 │と同じスタック・フレーム
      │hl of PcCntxt_return2Task をここに移動する。== HLret2 │構造となる。
      ├───────┤                                      │
      │PcCntxt_return2Task(.) への return address            │PcCntxt_return2Task()
      ├───────┤                                      │を呼び出すことで作られ
      │inDamieAt[0] in PcCntxt_executeLoopPolling(.)         │る Stack データ構造。
      ├───────┤                                      │
      │inDamieAt[1] in PcCntxt_executeLoopPolling(.)         │これに対する相対位置に
      ├───────┤                                      │タスク側のデータを
      │inDamieAt[2] in PcCntxt_executeLoopPolling(.)         │設定する処理を、
      ├───────┤                                      │PcCntxt_return2Task()
      │inDamieAt[3] in PcCntxt_executeLoopPolling(.)         │が行う。
      ├───────┤                                      │
      │inDamieAt[4] in PcCntxt_executeLoopPolling(.)         │
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │

       task(const struct StDelayPcContext* pStDelayPcContextAg)
       TyByte PcCntxt_return2Task(const struct StDelayPcContext* pStDelayPcContextAg)
    と task() の開始呼び出しで PcCntxt_return2Task() の呼び出しだ同じスタック・フレーム
    を作ることを利用している

retrunFromTaskSub(kc struct StStackAndContext**, int) at 78K0

      void StkCntxt_setCallPrm(const struct StStackAndContext** cppStStackAndContextAg,...)
        
      │              │
      ├───────┤                                        
      │pfAt of StkCntxt_setCallPrm(.) ←-- hl,sp pointer       
      ├───────┤                                        
      │hl of PcCntxt_checkAndExecute(.) をここに移動する。== HLret2   
      ├───────┤                                        
      │StkCntxt_setCallPrm(.) への return address              
      ├───────┤                                        
      │cppStStackAndContextAg of StkCntxt_setCallPrm(.)        
      ├───────┤                                        
┌─┼┤inArg  of  StkCntxt_setCallPrm(.)                    │ここまでは task(.) と   
│    ├───────┤                                      │る Stack データ構造。
│    │              │                                       
│
│
│    TyWord StkCntxt_call(const struct StStackAndContext** cppStStackAndContextAg
│    を実行することで作りあげるスタック・フレーム
│
│    ├───────┤                                        
│    │              │                                        
│  ●├───────┤HLref2                                  
│    │pStStackAndContext ←cppStStackAndContextAg of pfAg(.)│ここまでは task(.)
│    ├───────┤                                      │と同じスタック・フレーム
│  ○│hl of PcCntxt_return2Task をここに移動する。== HLret2 │構造となる。
│    ├───────┤                                      │
│    │PcCntxt_return2Task(.) への return address            │PcCntxt_return2Task()
│    ├───────┤                                      │を呼び出すことで作られ
└→  │inDamieAt in PcCntxt_executeLoopPolling(.)         │
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │


      TyWord StkCntxt_call(const struct StStackAndContext** cppStStackAndContextAg

      │              │
      ├───────┤                                        
      │pStPcContextAt ←-- hl,sp pointer
      ├───────┤                                        
0xfb34│cppStAg  of StkCntxt_call(.)                          │ここまでは task(.)
      ├───────┤                                      │と同じスタック・フレーム
      │hl of PcCntxt_return2Task をここに移動する。== HLret2 │構造となる。
      ├───────┤                                      │
0xfb38│StkCntxt_call(.) への return address                  │PcCntxt_return2Task()
      ├───────┤                                      │を呼び出すことで作られ
0xfb3a│chAt          │ ←┐hl,sp                            │0x00: 1 byte
      ├───────┤   │                                 │  
      │inAt               │                                 │  
      ├───────┤   │                                 │  
fb3e●│pStDelayPcContextAg↓of PcCntxt_return2Task(.) HLref2 │0x0084
      ├───────┤                                      │
      │hl of PcCntxt_return2Task をここに移動する。== HLret2 │0xfb44 ここに pfTaskSub を入れる。
      ├───────┤                                      │
0xfb42│PcCntxt_return2Task(.) への return address            │0x0668
      ├───────┤                                      │を呼び出すことで作られ
0xfb44│inDamieAt:1  in PcCntxt_executeLoopPolling(.)         │る Stack データ構造。
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │
      │              │
      StkCntxt_call(.) で ret命令を実行する直前のデータ配置

      │              │
      ├───────┤                                        
    ●│pStStackAndContext:0xfbcc
      ├───────┤                                        
    ○│pfAg          │←  SP, hl==hl of PcCntxt_checkAndExecute(.),ax==pStStackAndContext
      ├───────┤                                        
      │PcCntxt_return2Task(.) への return address            │
      ├───────┤                                      │
      │inDamieAt    in PcCntxt_executeLoopPolling(.)         │
      ├───────┤                                      │ここまでは task(.)関数が
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │スタックに積む
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │

TyWord StkCntxt_call( struct StStackAndContext** cppStAg)
      │              │
      ├───────┤
      │pStPcContextAt│←┐hl,sp at PcCntxt_suspend(.)
      ├───────┤
      │pStStateDelayAt
      ├───────┤
0xfb34│ppStDelayPcContextAg                                  │0xfb3e 
      ├───────┤
      │HL            │                                      │0xfb3a
      ├───────┤
0xfb38│return address of PcCntxt_suspend(.)                  │0x083f
      ├───────┤ 
0xfb3a│chAt          │ ←┐hl,sp                            │0x00: 1 byte
      ├───────┤   │                                 │  
      │inAt               │                                 │  
      ├───────┤   │                                 │  
fb3e●│pStDelayPcContextAg↓of PcCntxt_return2Task(.) HLref2 │0x0084
      ├───────┤                                      │
      │hl of PcCntxt_return2Task をここに移動する。== HLret2 │0xfb44
      ├───────┤                                      │
0xfb42│PcCntxt_return2Task(.) への return address            │0x0668
      ├───────┤                                      │を呼び出すことで作られ
0xfb44│inDamieAt:1  in PcCntxt_executeLoopPolling(.)         │る Stack データ構造。
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │
void StkCntxt_returnFromTaskSub( struct StStackAndContext** cppStAg)
      │              │
      ├───────┤
      │pStPcContextAt│←┐hl,sp at PcCntxt_suspend(.)
      ├───────┤
      │pStStateDelayAt
      ├───────┤
0xfb34│ppStDelayPcContextAg                                  │0xfb3e 
      ├───────┤
      │HL            │                                      │0xfb3a
      ├───────┤
0xfb38│return address of PcCntxt_suspend(.)                  │0x083f
      ├───────┤ 
0xfb3a│chAt          │ ←┐hl,sp                            │0x00: 1 byte
      ├───────┤   │                                 │  
      │inAt               │                                 │  
      ├───────┤   │                                 │  
fb3e●│pStDelayPcContextAg↓of PcCntxt_return2Task(.) HLref2 │0x0084
      ├───────┤                                      │
      │hl of PcCntxt_return2Task をここに移動する。== HLret2 │0xfb44
      ├───────┤                                      │
0xfb42│PcCntxt_return2Task(.) への return address            │0x0668
      ├───────┤                                      │を呼び出すことで作られ
0xfb44│inDamieAt:1  in PcCntxt_executeLoopPolling(.)         │る Stack データ構造。
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │
    start task and suspend 動作の一例( 2 個の auto variable)

      │              │
      ├───────┤
      │pStPcContextAt│←┐hl,sp at PcCntxt_suspend(.)
      ├───────┤
      │pStStateDelayAt
      ├───────┤
0xfb34│ppStDelayPcContextAg                                  │0xfb3e 
      ├───────┤
      │HL            │                                      │0xfb3a
      ├───────┤
0xfb38│return address of PcCntxt_suspend(.)                  │0x083f
      ├───────┤ 
0xfb39│chAt          │ ←┐hl,sp                            │0x00: 1 byte
      ├───────┤   │                                 │  
      │inAt               │                                 │  
      ├───────┤   │                                 │  
fb3e●│pStDelayPcContextAg↓of PcCntxt_return2Task(.) HLref2 │0x0084
      ├───────┤                                      │
      │hl of PcCntxt_return2Task をここに移動する。== HLret2 │0xfb44
      ├───────┤                                      │
0xfb42│PcCntxt_return2Task(.) への return address            │0x0668
      ├───────┤                                      │を呼び出すことで作られ
      │inDamieAt    in PcCntxt_executeLoopPolling(.)         │る Stack データ構造。
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │

    PcCntxt_return2Task 動作の一例(testTask に戻る)

      │              │
      ├───────┤
      │pStPcContextAt│←┐hl,sp at PcCntxt_suspend(.)
      ├───────┤
      │pStStateDelayAt
      ├───────┤
0xfb32│ppStDelayPcContextAg                                  │0xfb3e 
      ├───────┤
      │HL            │                                      │0xfb3a
      ├───────┤
0xfb36│return address of PcCntxt_suspend(.)                  │0x083f
      ├───────┤ 
0xfb38│byReturnValueAt  ←┐hl,sp
      ├───────┤   │                                   
      │pStPcContextAt     │
      ├───────┤   │                                   
      │pStStateDelayAt    │                                   
      ├───────┤   │                                   
fb3e●│pStDelayPcContextAg↓of PcCntxt_return2Task(.) HLref2 │0x0084
      ├───────┤                                      │
      │hl of PcCntxt_return2Task をここに移動する。== HLret2 │0xfb44
      ├───────┤                                      │
0xfb42│PcCntxt_return2Task(.) への return address            │0x067A
      ├───────┤                                      │を呼び出すことで作られ
0xfb44│inDamieAt    in PcCntxt_executeLoopPolling(.)         │る Stack データ構造。
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │

    PcCntxt_return2Task 動作の一例(testTask に戻る) at PcCntxt_executeLoopPolling(.)

      │              │
      ├───────┤
0xfb40│inReturnValueAt  ←┐hl,sp
      ├───────┤   │                                   
      │pStPcContextAt     │
      ├───────┤   │                                   
      │pStStateDelayAt    │                                   
      ├───────┤   │                                   
fb3e●│pStDelayPcContextAg↓of PcCntxt_return2Task(.) HLref2 │0xfb74
      ├───────┤                                      │
      │hl of PcCntxt_return2Task をここに移動する。== HLret2 │0xfb4c
      ├───────┤                                      │
0xfb4a│PcCntxt_return2Task(.) への return address            │0x06f5
      ├───────┤                                      │を呼び出すことで作られ
0xfb4c│inDamieAt    in PcCntxt_executeLoopPolling(.)         │る Stack データ構造。
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │



        PcCntxt_call 動作の一例

      │              │
      ├───────┤
0xfb34│ppStDelayPcContextAg                                  │0xfb3e 
      ├───────┤
      │HL            │                                      │0xfb3a
      ├───────┤
0xfb38│return address of PcCntxt_call(&pStDelayPcContextAg)  │0x0a06
      ├───────┤ 
0xfb3a│chAt
      ├───────┤                                      
      │inAt
      ├───────┤                                      
fb3e●│pStDelayPcContext Ag of PcCntxt_return2Task(.) HLref2 │0xfb74 → de = pStDelayPcContext
      ├───────┤                                      │
      │hl of PcCntxt_return2Task をここに移動する。== HLret2 │0xfb44 → 関数address ←→ hl value, sp
      ├───────┤                                      │
0xfb42│PcCntxt_return2Task(.) への return address            │0x067A
      ├───────┤                                      │を呼び出すことで作られ
0xfb44│inDamieAt    in PcCntxt_executeLoopPolling(.)         │る Stack データ構造。
      ├───────┤                                      │
      │pStStateDelayAt in PcCntxt_executeLoopPolling(.)      │
      ├───────┤                                      │
      │return address│                                      │
      ├───────┤                                      │
      │              │


    IntCntxt_suspend 動作の一例(testTsk2 に戻る)

0xfb2c│ppStDelayPcContextAg  of PcCntxt_suspend(.)           │0xfb32
      ├───────┤                                      │
      │hl of task                をここに移動する。== HLret2 │0xfb32
      ├───────┤                                      │
0xfb30│IntCntxt_suspend(ppStPcContestAg) の return address   │0x0b7A
      ├───────┤                                      │を呼び出すことで作られ
fb32●│pStPcContextAg  in PcCntxt_startImmediately(.)        │0fbae
      ├───────┤                                      │
0xfb34│HL            │                                      │0b38
      ├───────┤                                      │
0xfb36│return address│of task(pStPcContextAt, inAg.)        │0706
      ├───────┤                                      │
0xfb3e│              │                                      │
      ├───────┤                                      │
      │              │


    IntCntxt_return2Task 動作の一例(testTask に戻る)

      │task 側への戻りアドレス・飛び先                       │0x0b8c
      ├───────┤                                      │を呼び出すことで作られ
fb34●│pStStateDelayAg in IntCntxt_return2Task(pStPcContextAg│0fbae
      ├───────┤                                      │
0xfb36│HL            │                                      │0xfb3a
      ├───────┤                                      │
0xfb38│return address│of IntCntxt_return2Task(pStPcContextAg)│ 0x91c
      ├───────┤                                      │
0xfb3a│inDamieAt    in PcCntxt_executeLoopPolling(.)         │0x0009
      ├───────┤                                      │
      │              │

ドキュメント・メモ

    1h 78K0 context switch
    IntCntxt
    e←-- IntOOP.h を include するだけで使えるはず
    e←-- PcCntxt_executeLoopPolling() と task polling() を同じ優先度で実行すべき
        ではない。main loop の最後におくべきである。
        ←-- CntxtGrp_lastPolling() を追加する