	.h8300h
;---------------------------------------------------------------;
; コオペレーティブなマルチタスク(これ以上単純なマルチタスクはない(^^;)
; ラウンドロビン/４タスク固定
;    タスク0(メインタスク)内 で SwitchTask をコールすると タスク 1 に切り替わる
;    タスク1内 で SwitchTask をコールすると タスク 2 に切り替わる
;    タスク2内 で SwitchTask をコールすると タスク 3 に切り替わる
;    タスク3内 で SwitchTask をコールすると タスク 0 に切り替わる
;
; +-> タスク0(メインタスク) -> タスク1 -> タスク2 -> タスク3 ->
; |                                                            |
; +------------------------------------------------------------+
;	スタックは各タスクの必要量を確保すること
;	各タスクは，無限ループにすること
;	大きな配列は，static にしたほうが，安全である．
;
;使用方法
;	void main( void )
;	{
;		InitMultiTask() ;		//まず、初期化
;		InitTask1( Task1Loop, Task1Stack ) ;
;		InitTask2( Task2Loop, Task2Stack ) ;
;		InitTask3( Task3Loop, Task2Stack ) ;
;		for(;;){
;			SwitchTask() ;
;			.
;			.
;			.
;		}
;	}
;	void Task1Loop( void )
;	{
;		for(;;){
;			SwitchTask() ;
;			.
;			.
;			.
;		}
;	}
;	void Task2Loop( void )
;	{
;		for(;;){
;			SwitchTask() ;
;			.
;			.
;			.
;		}
;	}
;	void Task3Loop( void )
;	{
;		for(;;){
;			SwitchTask() ;
;			.
;			.
;			.
;		}
;	}
;---------------------------------------------------------------;

	.global	_InitMultiTask
	.global	_SwitchTask
	.global	_InitTask0
	.global	_InitTask1
	.global	_InitTask2
	.global	_InitTask3
	.global	_InitTask4
	.global	_InitTask5
	.global	_InitTask6

	.global	_TaskStackPointer

;******************************************************************************
;	マルチタスクシステムの初期化	void InitMultiTask( void )
;******************************************************************************
_InitMultiTask:
	sub.b		r0l,r0l
	mov.b		r0l,@CurrentTaskNo
	rts

;******************************************************************************
;	タスクスイッチング				void SwitchTask( void )
;******************************************************************************
_SwitchTask:
	push.l		er3
	push.l		er4
	push.l		er5
	push.l		er6

	;****************************
	; er0 = CurrentTaskNo * 2
	;****************************
	sub.l		er0,er0
	mov.b		@CurrentTaskNo,r0l	;
	add.l		er0,er0				;bra xx が2バイトの命令であるため2倍する
	add.l		#TaskJumpTable,er0	;
	jmp			@er0					;のいずれかにジャンプ

TaskJumpTable:							;ジャンプテーブル
	bra			Task0to1
	bra     	Task1to2
	bra     	Task2to3
	bra     	Task3to4
	bra     	Task4to5
	bra     	Task5to6
	bra     	Task6to0

Task0to1:
	mov.l		sp,@Task0Sp
	mov.l		@Task1Sp,sp
	bra			EndOfTaskSw

Task1to2:
	mov.l		sp,@Task1Sp
	mov.l		@Task2Sp,sp
	bra			EndOfTaskSw

Task2to3:
	mov.l		sp,@Task2Sp
	mov.l		@Task3Sp,sp
	bra			EndOfTaskSw

Task3to4:
	mov.l		sp,@Task3Sp
	mov.l		@Task4Sp,sp
	bra			EndOfTaskSw

Task4to5:
	mov.l		sp,@Task4Sp
	mov.l		@Task5Sp,sp
	bra			EndOfTaskSw

Task5to6:
	mov.l		sp,@Task5Sp
	mov.l		@Task6Sp,sp

EndOfTaskSw:
	mov.b		@CurrentTaskNo,r0l	;CurrentTaskNoをインクリメント
	add.b		#1,r0l
	mov.b		r0l,@CurrentTaskNo

ReturnToTask:							;タスク切り替え処理終了
	pop.l		er6
	pop.l		er5
	pop.l		er4
	pop.l		er3
	rts

Task6to0:
	mov.l		sp,@Task6Sp
	mov.l		@Task0Sp,sp

	sub.b		r0l,r0l					;CurrentTaskNo=0
	mov.b		r0l,@CurrentTaskNo

	bra			ReturnToTask

;******************************************************************************
;	タスク0の初期化			void InitTask1( void(*func)(void),char* Stack)
;										r0:program counter r1:stack
;******************************************************************************
_InitTask0:
	bsr			SetStack
	mov.l		er1,@Task0Sp
	rts

;******************************************************************************
;	タスク１の初期化			void InitTask1( void(*func)(void),char* Stack)
;										r0:program counter r1:stack
;******************************************************************************
_InitTask1:
	bsr			SetStack
	mov.l		er1,@Task1Sp
	rts

;******************************************************************************
;	タスク２の初期化
;******************************************************************************
_InitTask2:
	bsr			SetStack
	mov.l		er1,@Task2Sp
	rts
;******************************************************************************
;	タスク3の初期化
;******************************************************************************
_InitTask3:
	bsr			SetStack
	mov.l		er1,@Task3Sp
	rts
;******************************************************************************
;	タスク4の初期化
;******************************************************************************
_InitTask4:
	bsr			SetStack
	mov.l		er1,@Task4Sp
	rts

;******************************************************************************
;	タスク4の初期化
;******************************************************************************
_InitTask5:
	bsr			SetStack
	mov.l		er1,@Task5Sp
	rts

;******************************************************************************
;	タスク4の初期化
;******************************************************************************
_InitTask6:
	bsr			SetStack
	mov.l		er1,@Task6Sp
	rts

;******************************************************************************
;	スタックの内容(6ワード)を r0(PC) でセット(push PC × 6)
;******************************************************************************
SetStack:
	and.b		#0xfe:8,r1l					;必ず偶数番地にする(馬鹿避け)
	mov.l		er0,@-er1					;r3,r4,r5,r6,pc の分
	mov.l		er0,@-er1
	mov.l		er0,@-er1
	mov.l		er0,@-er1
	mov.l		er0,@-er1
	rts


	.global	Task0Sp
	.section .data
	.align 2

_TaskStackPointer:
Task0Sp:
	.space 4
Task1Sp:
	.space 4
Task2Sp:
	.space 4
Task3Sp:
	.space 4
Task4Sp:
	.space 4
Task5Sp:
	.space 4
Task6Sp:
	.space 4

CurrentTaskNo:
	.space 1
	.end

