思うだけで学ばない日記 2.0

思うだけで学ばない日記から移転しました☆!よろしくお願いします。

マイクロスレッド基本おさらい(3)

>果たしてこんなロジックで動くのか?
SH3+SH-Cで動かしてみますた*1

mth_core.src
          .EXPORT     _exec
          .EXPORT     _suspend
          .EXPORT     _resume
          .SECTION    P,CODE,ALIGN=4


;*------------------------------------------------------------------------*
; <仮定>
;   typedef struct t_ctx {
;     size_t stksz;
;     TStkElem* ssp;
;     TStkElem stk[1];
;   } TCtx;
;   TStkElem: スタックに格納されるデータのうち、整合の制限が最も強い型
;             (SH3ではlongが適切)
;*------------------------------------------------------------------------*


;*------------------------------------------------------------------------*
; void exec(TCtx* p_ctx, void (*bar)(void))
;*------------------------------------------------------------------------*
_exec:
          MOV.L       R14,@-R15
          MOV.L       R13,@-R15
          MOV.L       R12,@-R15
          MOV.L       R11,@-R15
          MOV.L       R10,@-R15
          MOV.L       R9,@-R15
          MOV.L       R8,@-R15
          STS.L       PR,@-R15
          ; p_ctx->ssp = p_ctx->stk + p_ctx->stksz
          MOV.L       @(0,R4),R1  ; R1 = p_ctx->stksz
          MOV.L       @(8,R4),R2  ; R2 = p_ctx->stk
          ADD         R2,R1       ; R1 = (char*)stk + stksz
          MOV.L       R1,@(4,R4)  ; p_ctx->ssz = R1 (== (char*)stk + stksz)
          ; swap(SP, p_ctx->ssp)
          MOV         R15,R1
          MOV.L       @(4,R4),R15
          MOV.L       R1,@(4,R4)
          ;
          LDS         R5,PR       ; PR = bar
          RTS
          NOP


;*------------------------------------------------------------------------*
; void suspend(TCtx* p_ctx)
;*------------------------------------------------------------------------*
_suspend:
          MOV.L       R14,@-R15
          MOV.L       R13,@-R15
          MOV.L       R12,@-R15
          MOV.L       R11,@-R15
          MOV.L       R10,@-R15
          MOV.L       R9,@-R15
          MOV.L       R8,@-R15
          STS.L       PR,@-R15
          ; swap(SP, p_ctx->ssp)
          MOV         R15,R1
          MOV.L       @(4,R4),R15
          MOV.L       R1,@(4,R4)
          ;
          LDS.L       @R15+,PR
          MOV.L       @R15+,R8
          MOV.L       @R15+,R9
          MOV.L       @R15+,R10
          MOV.L       @R15+,R11
          MOV.L       @R15+,R12
          MOV.L       @R15+,R13
          MOV.L       @R15+,R14
          RTS
          NOP


;*------------------------------------------------------------------------*
; void resume(TCtx* p_ctx)
;*------------------------------------------------------------------------*
_resume:
          BRA         _suspend
          NOP


          .END
mth_sample.c
#include 

typedef long TStkElem;

typedef struct t_ctx {
  size_t stksz;
  TStkElem *ssp;
  TStkElem stk[4096/sizeof(TStkElem)];
} TCtx;

extern void exec(TCtx *p_ctx, void (*bar)(void));
extern void suspend(TCtx *p_ctx);
extern void resume(TCtx *p_ctx);

TCtx ctx = { 4096 };

void bar(void);

main(void)
{
  exec(&ctx, bar);
  for (;;) {
    printf("Hello ");
    printf("World!\n");
    resume(&ctx);
  }
}

void bar(void)
{
  for (;;) {
    printf("This is ");
    printf("a pen.\n");
    suspend(&ctx);
  }
}
実行結果
This is a pen.
Hello World!
This is a pen.
Hello World!
This is a pen.
Hello World!
This is a pen.
Hello World!
(...以下略...)

上記mth_sample.cは、main()で"Hello "と"World!\n"を表示し、bar()で"This is "と"a pen.\n"を表示するプログラムである。表示は上記実行結果のように"This is a pen."と"Hello World!"が規則正しく交代し、決して"Hello a pen."になったり、"This is World!"になったりはしない。

main()が通常(非マイクロスレッド)コンテキスト、bar()がマイクロスレッドコンテキストで実行されている。

*1:上記訂正を受けて、TCtxのメンバにローカルスタックサイズstkszを追加してあります。(ただしこの形態を最終形とするかどうかは後日考える。)