/*
 *  TOPPERS/JSP Kernel
 *      Toyohashi Open Platform for Embedded Real-Time Systems/
 *      Just Standard Profile Kernel
 * 
 *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
 *                              Toyohashi Univ. of Technology, JAPAN
 *                     2003         by Advanced Data Controls, Corp
 * 
 *  上記著作権者は，以下の (1)〜(4) の条件か，Free Software Foundation 
 *  によって公表されている GNU General Public License の Version 2 に記
 *  述されている条件を満たす場合に限り，本ソフトウェア（本ソフトウェア
 *  を改変したものを含む．以下同じ）を使用・複製・改変・再配布（以下，
 *  利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，その適用可能性も
 *  含めて，いかなる保証も行わない．また，本ソフトウェアの利用により直
 *  接的または間接的に生じたいかなる損害に関しても，その責任を負わない．
 * 
 *  @(#) $Id: cpu_support.sh,v 1.4 2003/12/19 11:48:37 honda Exp $
 */


#define _MACRO_ONLY
#include "jsp_kernel.h"
#include "offset.h"
#include <t_config.h>
 			

/*GHS アセンブラ擬似命令変換*/
#define	long	data.l
#define	org	offset

/*GHS ROMモニタ割り込みエントリーアドレス*/
#ifdef 	GHS_STUB
#define	_CpuExceptionHandler	0xa0000848
#endif


/*
 *  例外/割り込み出入り口処理ルーチン
 *  SH3はベクタテーブルを持たず、例外,TRAPAが発生するとVBR+0x100番地を、
 *  内部/外部/NMI割り込みが発生すると、VBR+0x600番地を実行する。
 */
        
/*
 *	VBR に設定する値
 */
    .section .text
    .align 2        
    .global _BASE_VBR
_BASE_VBR:
     bra _start
     nop
     nop
     nop

/*
 *  Exception 100 vector
 *  アドレスエラー,スロット不当命令例外、Trapa例外等が発生すると実行される。
 *
 *  CPU例外ハンドラは、非タスクコンテキストで実行する、そのため、CPU例外ハン
 *  ドラを呼び出す前に例外/割り込みを示すレジスタバンク1の r7 レジスタをイン
 *  クメントし、リターンしてきた後にデクリメントする。CPU例外がタスクコンテキ
 *  ストで発生し、regflg が TRUE になった時に、 ret_exc へ分岐する。
 *  regflg をチェックする前に割り込みを禁止しないと、reqflg をチェック後に起
 *  動された割り込みハンドラ内でディスパッチが要求された場合に、ディスパッチ
 *  されない。
 *
 *		
 *  例外が発生すると、例外発生元のコンテキストであるspc,pr,ssr,r0〜r7を退避
 *  する。例外が発生した時点でのコンテキストを調べ非タスクコンテキストなら
 *  _exception_from_intから実行を開始する。例外の要因はEXPEVTレジスタ読み、
 *  exc_tableからCPU例外ハンドラの開始番地を読み込む。発生した例外に対して
 *  CPU例外ハンドラが登録されていなければ、_no_reg_exceptionにブランチして、
 *  ssr,sr,spc,prの内容を出力して停止する。CPU例外ハンドラからリターンして
 *  きたら、reqflgを調べ0以外ならrec_exc()に飛び、0なら元の処理にリターンす
 *  る。
 *
 *
 *  BLビットの扱いについて
 *  ssr,spc に戻り先のコンテキストを戻して rte を発行する際には，割込み（NMI 
 *  も含む）を受け付けないように BL ビットを1にする必要がある．例外/割込みハ
 *  ンドラ終了時には BL をビットを1にせず IPM を MAX_IPM に設定する．これは，
 *  BL ビットが1の場合に例外が発生すると CPU がリセットされることを考慮して，
 *  安全のため，ssr,spcを復帰する直前でBLを1に設定している．
 *       
 */	
			

    .org   0x0100              /*  _BASE_VBR + 0x0100番地に配置   */
    .align 2
    .global _general_exception
_general_exception:
#ifdef GHS_STUB /* GHS */
	mov.l	r0,@-r15
	mov.l	r1,@-r15
	mov.l   _expevt,r0
	mov.l   @r0,r1     
	shlr2   r1           
	shlr    r1
	mov.l   _exc_table_exc,r0
	mov.l   @(r0,r1),r0        
	tst     r0,r0
	mov.l	@r15+,r1	
	mov.l	@r15+,r0
	bt      _rom_exception   /* _rom_exceptionへジャンプ             */
#endif
 /* spc,pr,ssr をスタックに保存する */
    stc.l  spc,@-r15          
    sts.l  pr,@-r15               
    stc.l  ssr,@-r15
    stc.l  gbr,@-r15					
    sts.l  macl,@-r15					
    sts.l  mach,@-r15
    stc.l  r0_bank,@-r15 /* 例外発生時のr0〜r7を保存        */    
    stc.l  r1_bank,@-r15
    stc.l  r2_bank,@-r15
    stc.l  r3_bank,@-r15
    stc.l  r4_bank,@-r15
    stc.l  r5_bank,@-r15
    stc.l  r6_bank,@-r15    
    stc.l  r7_bank,@-r15
    tst    r7,r7               /* 例外発生元のコンテキストを判定            */
    bf/s   _exception_from_exc /* 発生元が例外/割り込みハンドラならジャンプ */
     add    #0x01,r7	       /* 例外/割り込みネスト回数をインクリメント   */
    mov    r15,r1              /* 戻り先が割り込みハンドラでないのでスタッ  */
    mov.l  _stacktop_exc,r15   /* クを入れ替え元のスタックポインタを保存    */ 
    mov.l r1,@-r15            
#ifdef GHS_HOOK
	mov.l   r1,@-r15
	mov.l   r7,@-r15
	stc     spc,r0
	mov.l   r0,r5
	mov.l   _expevt,r0        /* 割り込み許可すると消えるレジスタを保存    */
	mov.l   _exception_hook_dis,r2
	jsr     @r2
	mov.l   @r0,r4            /* EXPEVTレジスタを取得		              */
	mov.l   @r15+,r7
	mov.l   @r15+,r1
#endif

    mov.l  _expevt,r0          /* 例外を許可すると消えるレジスタを保存      */
    mov.l  @r0,r5              /* EXPEVTレジスタを取得                      */
    ldc    r1,r4_bank          /* CPU例外ハンドラへの引数                   */
    ldc    r5,r5_bank	     
    mov.l  _unmak_rb_bl_exc,r2 /* BLビットを0に，レジスタバンクを切り替え   */
    stc    sr,r3               
    and    r3,r2			
    ldc    r2,sr               
    shlr2  r5                  /* EXPEVTを3ビット右シフト                   */
    shlr   r5                
    mov.l  _exc_table_exc,r0   /* exc_tableのアドレスをr0に                 */
    mov.l  @(r0,r5),r2         /* ハンドラのアドレスを取得                  */
    tst    r2,r2               /* ハンドラが登録されていない例外なら        */
    bt     _no_reg_exception   /* no_reg_exceptionへジャンプ                */
    jsr    @r2                 /* CPU例外ハンドラへ                         */
     nop
    mov.l  _mask_md_ipm_exc,r0
    ldc    r0,sr               /* 割り込み禁止                              */
    stc    r7_bank,r7          /* 例外/割り込みのネスト回数をデクリメント   */
    dt     r7
    ldc    r7,r7_bank
    mov.l  _reqflg_exc,r2      /* reqflgのチェック                          */
    mov.l  @r2,r1
    tst    r1,r1               /* reqflgがFALSEならret_to_task_excに飛び    */
    bt/s   _ret_to_task_exc    /* タスクに戻る                              */
     mov.l  @r15,r15           /* 戻り先がタスクなのでスタックを戻す        */
    xor    r0,r0               
    bra    ret_exc
     mov.l  r0,@r2             /* reqflgをクリア                            */


/*
 *   exception_from_int
 *   CPU例外発生時のコンテキストが非タスクコンテキストの場合の処理
 *   タスクコンテキストの場合との処理の違いは、とCPU例外ハンドラの
 *   処理が終了すると必ず元の処理に戻ることである。
 */
	
_exception_from_exc:
#ifdef GHS_HOOK
	mov.l   r7,@-r15
	stc     spc,r0
	mov.l   r0,r5
	mov.l   _expevt,r0       /* 割り込み許可すると消えるレジスタを保存    */
	mov.l   _exception_hook_dis,r2
	jsr     @r2
	mov.l   @r0,r4           /* EXPEVTレジスタを取得                      */
	mov.l   @r15+,r7
	
#endif
    mov.l   _expevt,r0        /* 例外を許可すると消えるレジスタを保存      */
    mov.l   @r0,r5            /* EXPEVTレジスタを取得                      */
    ldc     r15,r4_bank       /* CPU例外ハンドラへの引数                   */
    ldc     r5,r5_bank	     
    mov.l   _unmak_rb_bl_exc,r2 /* BLビットを0に，レジスタバンクを切り替え */
    stc     sr,r3
    and     r3,r2			
    ldc     r2,sr               
    shlr2   r5                /* EXPECTを3ビット右シフト                   */
    shlr    r5                	
    mov.l   _exc_table_exc,r0 /* exc_tableのアドレスをr0に                 */
    mov.l   @(r0,r5),r2       /* ハンドラのアドレスを取得                  */
    tst     r2,r2             /* ハンドラが登録されていない例外なら        */
    bt      _no_reg_exception /* no_reg_exceptionへジャンプ                */
    jsr     @r2               /* CPU例外ハンドラへ                         */
     nop
    mov.l  _mask_md_ipm_exc,r0
    ldc    r0,sr              /* BL=1,割り込み禁止                         */
    stc    r7_bank,r7         /* 例外/割り込みのネスト回数をデクリメント   */
    dt     r7
    ldc    r7,r7_bank
_ret_to_task_exc:
    mov.l  @r15+,r7           /* r0〜r1,ssr,pr,spcを復帰しタスクに戻る     */
    mov.l  @r15+,r6
    mov.l  @r15+,r5
    mov.l  @r15+,r4
    mov.l  @r15+,r3
    mov.l  @r15+,r2
    mov.l  @r15+,r1        
    mov.l  _mask_md_bl_exc,r0 
    ldc    r0,sr             /* BLを1に                                   */
    mov.l  @r15+,r0
    lds.l  @r15+,mach                
    lds.l  @r15+,macl        
    ldc.l  @r15+,gbr               
    ldc.l  @r15+,ssr            
    lds.l  @r15+,pr
    ldc.l  @r15+,spc
    rte
     nop

#ifdef GHS_STUB /* GHS */
_rom_exception:
	stc.l	ssr,@-r15
	stc.l	spc,@-r15
	mov.l	r0,@-r15
	mov.l	r1,@-r15
	mov.l	L._CpuException1,r1
	jmp	@r1
	mov	#1,r0

	.align	4
L._CpuException1:
	.data.l	_CpuExceptionHandler
#endif

/*	
 *  no_reg_exception()
 *  CPU例外として登録されていない例外が発生すると呼び出される
 *  例外コード、例外が発生した時点のpc,sr,prを出力してカーネル
 *  を停止する。
 */					
_no_reg_exception:
    mov.l  _expevt,r5
    mov.l  @r5,r4
    stc    spc,r5
    stc    ssr,r6
    sts    pr,r7
    mov.l  _cpu_expevt_k,r1
    jsr    @r1
     nop

	.align  4
_stacktop_exc:
    .long  STACKTOP            /* タスク独立部のスタックの初期値  */
_expevt:	
    .long  EXPEVT
_exc_table_exc:	
    .long  _exc_table
_unmak_rb_bl_exc:		
    .long  0x4fffffff
_mask_md_ipm_exc:	
    .long  0x40000000 + MAX_IPM << 4	
_reqflg_exc:
    .long  _reqflg
_cpu_expevt_k:	
    .long  _cpu_expevt	
_mask_md_bl_exc:	
    .long  0x50000000 + MAX_IPM << 4	

#ifdef GHS_HOOK
	.global _exception_hook
_exception_hook_dis:
	.long   _exception_hook
#endif


	
/*
 *  タスクディスパッチャ
 *
 *  _dispatch は、r7_bank1 = 0,割込み禁止状態で呼び出さなければならな
 *  い．_exit_and_dispatch も，r7_bank1 = 0・割込み禁止状態で呼び出す
 *  のが原則であるが，カーネル起動時に対応するため，r7_bank1 = 1で呼び
 *  出した場合にも対応している．
 */

    .text
    .align 2
    .global _dispatch
_dispatch:
    sts.l  pr,@-r15         /* pr,r8〜r15 をスタックに保存           */
    mov.l  r14,@-r15        /* r0〜r7は呼び出し元で保存しているため  */    
    mov.l  r13,@-r15        /* 保存する必要が無い                    */    
    mov.l  r12,@-r15
    mov.l  r11,@-r15
    mov.l  r10,@-r15
    mov.l  r9, @-r15
    mov.l  r8, @-r15
    mov.l  _runtsk_dis,r2   /* r0 <- runtsk                          */
    mov.l  @r2,r0
    mov.l  r15,@(TCB_sp,r0) /* タスクスタックをTCBに保存 60以下ならOK*/		
    mov.l  dispatch_r_k,r1  /* 実行再開番地を保存                    */
    mov.l  r1,@(TCB_pc,r0)  /* 実行再開番地をTCBに保存  60以下ならOK */
    bra    dispatcher
     nop

dispatch_r:	
    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
    lds.l  @r15+,pr
    /*
     *  タスク例外処理ルーチンの起動
     *  dispatch_rはdispatcherから呼び出されるため，
     *  tcbのアドレスはr0に入っている．      
     */
    mov.l  @(TCB_enatex,r0),r1
    mov.l  _enatex_mask_dis,r2
    tst    r1,r2
    bt     dispatch_r_1         /* enatex が FALSE ならリターン */
    mov.l  @(TCB_texptn,r0),r1  /* texptnをロード               */
    tst    r1,r1
    bt     dispatch_r_1         /* texptn が 0で無ければ        */
    mov.l  _call_texrtn_dis,r1  /* タスク例外ルーチンの呼び出し */
    jmp    @r1        
     nop                          
dispatch_r_1:   
    rts
     nop                

    .global _exit_and_dispatch
_exit_and_dispatch:
    xor    r1,r1                 /* r7_bank1を0クリア             */
    ldc    r1,r7_bank
dispatcher:
    /*
     * ここには割り込み禁止で来ること
     */
    mov.l  _schedtsk_dis,r12    /* r0 <- schedtsk                   */
    mov.l  @r12,r0             
    cmp/eq #0,r0                /* schedtsk があるか？              */
    bt     dispatcher_1         /* 無ければジャンプ                 */
#ifdef GHS_HOOK 
	mov.l   _dispatch_hook_dis,r2
	jsr     @r2
	mov     r0,r4
	mov.l   @r12,r0
#endif

    mov.l  _runtsk_dis,r2
    mov.l  r0,@r2               /* schedtskをruntskに               */
    mov.l  @(TCB_sp,r0),r15     /* TCBからタスクスタックを復帰      */
    mov.l  @(TCB_pc,r0),r1      /* TCBから実行再開番地を復帰        */
    jmp    @r1 
     nop
dispatcher_1:
    /* イミディエイト値を毎回読み込むのは効率が悪いので事前に用意する
     * r8  : 割り込み禁止のためのSRの値   
     * r9  : 割り込み待ち中のSRの値
     * r10 : reqflgの番地
     * r11 : 0x01
     * r12 : 0x00
     * r13 : sleep中のSRの状態       
     */
    mov.l  _mask_md_ipm_dis,r8  /* 割り込み禁止のSRの値             */
#ifdef NO_SLEEP
    mov.l  _mask_md_dis,r9      /* 割り込み待ち中のSRの値           */        
#else
    mov.l  _mask_bl_md_dis,r9   /* 割り込み待ち中のSRの値           */
#endif                          
#ifdef SUPPORT_CHG_IPM
    mov.l  _task_intmask_k,r2
    mov.l  @r2,r3
    or     r3,r9
#endif
    mov.l  _reqflg_dis,r10
    mov    #0x01,r11
    xor    r12,r12
    mov.l  _stacktop_dis,r15   /* スタックを割り込みスタックに     */
    ldc    r11,r7_bank         /* r7_bank1 を1にして割り込み状態に */        
dispatcher_2:        
    /*
     *  ここで割込みモードに切り換えるのは，ここで発生する割込み処理
     *  にどのスタックを使うかという問題の解決と，割込みハンドラ内で
     *  のタスクディスパッチの防止という二つの意味がある．
     */
     /*
      *  割込み許可後にsleep命令を実行すると，割込み許可命令の実行前に
      *  割込み要求が入っている場合，割込み許可命令の実行と共に割込みが
      *  受け付けられその復帰後に，reqflgのチェックではなく sleep 状態
      *  に入ってしまう．
      *  この問題は，割込みの許可と sleep 状態への移行がアトミックに実
      *  行できないことに起因する．
      *  そのため，sleep 実行直前の SR 変更では BL ビットを'1'に設定す
      *  ることで，割込みの許可と sleep 状態への以降をアトミックに実行
      *  する．
      *  ldc r9,sr ではBLビットがセットされるため，割込みは受け付けずス
      *  リープモードに移行する．スリープモード中は，BLビットが1でも割
      *  込みを受け付けるため(SH7709ハードウェアマニュアル 8-10)，スリー
      *  プモードへの移行直後に割込みを受付スリープモードから復帰する．
      */
               
    ldc    r9,sr               /* 割り込みの許可                   */
#ifndef NO_SLEEP
    sleep                      /* 割込み待ち                       */
#endif /* NO_SLEEP */                
    ldc    r8,sr               /* 割り込み禁止                     */  
    mov.l  @r10,r7             /* r7 <- reqflg                     */
    tst    r7,r7               /* reqflg が FALSEなら              */
    bt     dispatcher_2        /* dispatcher_2 へ                  */
    ldc    r12,r7_bank         /* r7_bank1 をクリア                */        
    mov.l  r12,@r10            /* reqflg を FALSEに                */
    bra    dispatcher
     nop	
    .align 4
_runtsk_dis:	
    .long _runtsk
_schedtsk_dis:	
    .long _schedtsk
_enatex_mask_dis:    
    .long TCB_enatex_mask
_call_texrtn_dis:	
    .long _call_texrtn
_mask_md_ipm_dis:	
    .long 0x40000000 + MAX_IPM << 4
_mask_md_dis:	
    .long 0x40000000
_mask_bl_md_dis:	
    .long 0x50000000	        
dispatch_r_k:	
    .long dispatch_r
_stacktop_dis:
    .long STACKTOP           /* タスク独立部のスタックの初期値	*/
_reqflg_dis:
    .long  _reqflg
#ifdef GHS_HOOK
	.global _dispatch_hook
_dispatch_hook_dis:
	.long   _dispatch_hook
#endif


/* 
 *  割り込みハンドラ/CPU例外ハンドラ出口処理
 *
 * 戻り先がタスクでreqflgがセットされている場合のみここにくる。
 * r7_bank1 = 0,割り込み禁止状態,スクラッチレジスタを保存した
 * 状態で呼び出すこと。 
 *	
 */
    .text
    .align 2
    .globl ret_int
    .globl ret_exc
ret_exc:
ret_int:
    mov.l  _runtsk_ret,r1     /* r0 <- runtsk                  */
    mov.l  @r1,r0           
    mov.l  _enadsp_ret,r2     /* enadspのチェック              */
    mov.l  @r2,r3
    tst    r3,r3           
    bt     ret_int_1           
    mov.l  _schedtsk_ret,r4   /* r5 <- schedtsk                */ 
    mov.l  @r4,r5
    cmp/eq r0,r5              /* runtsk と schedtsk を比較     */
    bt     ret_int_1
    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
    mov    #TCB_sp,r1        /* タスクスタックを保存           */
    mov.l  r15,@(r0,r1)    
    mov.l  ret_int_r_k,r1    /* 実行再開番地を保存             */
    mov    #TCB_pc,r2	
    mov.l  r1,@(r0,r2)  
    bra    dispatcher
     nop
    
ret_int_r:
    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		
ret_int_1:
    /*
     *  タスク例外処理ルーチンの起動
     *  ret_int_r は dispatcher から呼び出されるため，tcbのアドレスはr0に
     *  入っている．
     *  なお，割込みの出口でタスクスイッチが発生しない場合はディスパッチャ
     *  を通らずに ret_int から直接 ret_int_1 に飛ぶ       
     */
    mov.l  @(TCB_enatex,r0),r1
    mov.l  _enatex_mask_ret,r2
    tst    r1,r2
    bt     ret_int_2            /* enatex が FALSE ならリターン  */
    mov.l  @(TCB_texptn,r0),r1  /* texptnをロード                */
    tst    r1,r1
    bt     ret_int_2            /* texptn が 0で無ければT<= 0    */
    mov.l _call_texrtn_ret,r1   /* タスク例外ルーチンの呼び出し  */
    jsr   @r1        
     nop       
ret_int_2:               
#ifdef SUPPORT_CHG_IPM
    mov    #32,r0
    mov.l  @(r0,r15),r1
    mov.l  _unmask_ipm,r2
    and    r2,r1
    mov.l  _task_intmask_k,r2
    mov.l  @r2,r3
    or     r3,r1
    mov.l  r1,@(r0,r15)
#endif /* SUPPORT_CHG_IMP */
    mov.l  @r15+,r7            /* spc,pr,ssr,スクラッチレジスタを復帰 */
    mov.l  @r15+,r6        
    mov.l  @r15+,r5
    mov.l  @r15+,r4
    mov.l  @r15+,r3
    mov.l  @r15+,r2
    mov.l  @r15+,r1
    mov.l  _mask_md_bl_ret,r0
    ldc    r0,sr               /* BLを1に                               */
    mov.l  @r15+,r0
    lds.l  @r15+,mach                
    lds.l  @r15+,macl        
    ldc.l  @r15+,gbr       
    ldc.l  @r15+,ssr    
    lds.l  @r15+,pr
    ldc.l  @r15+,spc
    rte
     nop
        
    .align 4
_runtsk_ret:
    .long _runtsk
_schedtsk_ret:	
    .long _schedtsk
_enadsp_ret:	
    .long _enadsp
ret_int_r_k:
    .long ret_int_r
_enatex_mask_ret:    
    .long TCB_enatex_mask        
_call_texrtn_ret:	
    .long _call_texrtn
_mask_md_bl_ret:	
    .long  0x50000000

/*
 *  タスク起動処理
 */ 
    .text
    .align 2
    .globl _activate_r
_activate_r:
    stc    sr,r0               /* 割り込み許可 */
    mov.l  _unmask_ipm,r1
    and    r1,r0	
#ifdef SUPPORT_CHG_IPM
    mov.l  _task_intmask_k,r1
    mov.l  @r1,r2
    or     r2,r0
#endif /* SUPPORT_CHG_IPM */
    ldc    r0,sr
    mov.l  @r15+,r1
    lds.l  @r15+,pr
    mov.l  @r15+,r4
    jmp    @r1
     nop
    .align 4
_unmask_ipm:
    .long  0xffffff0f
#ifdef SUPPORT_CHG_IPM		
_task_intmask_k:
    .long _task_intmask
#endif /* SUPPORT_CHG_IPM */
		
		
/*
 *  Exception 600 vector
 *  割り込みが発生すると実行される。		
 *
 *
 *  SH3は割り込みが発生するとすべてVBR+0x600番地からプログラムを実行するため、
 *  ここに配置するルーチンでまずスタックの切り替え、レジスタの保存,IPMの設定,
 *  割り込み要因の判定を行いその後BLビットを0にして割り込みハンドラを呼ぶ必要
 *  がある。
 *  割り込み要因に対応した割り込みハンドラの開始番地は配列int_table[]に登録し
 *  て呼び出す。オフセットの計算は、割り込み要因レジスタを右に2ビットシフトし
 *  て行う。割り込み要因レジスタはSH7708ではINTEVTレジスタにセットされるが、
 *  SH7709およびSH7709AではINTEVT2にセットされるため、ifdefにより切り分けてい
 *  る。また、一部のディバイスについて割り込み要因レジスタで渡される値とIPMと
 *  の間には関係がないため、各割り込み要因に対応したIPMを持つSRの内容を配列
 *  int_plevel_table[]に登録してそれを読み出す。
 *
 *  reqflg をチェックする前に割込みを禁止しないと，reqflg をチェック後
 *  に起動された割込みハンドラ内でディスパッチが要求された場合に，ディ
 *  スパッチされない．
 *
 */

    .org    0x0600        /* _BASE_VBR + 0x0600番地に配置 */
    .align 2
    .global _interrupt
_interrupt:    
#ifdef GHS_STUB
	mov.l	r0,@-r15
	mov.l	r1,@-r15
	mov.l   _intevt,r0 
	mov.l   @r0,r1     
	shlr2   r1           
	shlr    r1
/*	mov.l   _int_table_k,r0
	mov.l   @(r0,r1),r0
*/	
	mov.l	@r15+,r1
	mov.l	@r15+,r0
	bt      _rom_interrupt   
#endif
    stc.l  spc,@-r15       /* 多重割り込みが入ると消えてしまうので        */
    sts.l  pr,@-r15        /* spc,pr,ssr,gbr,macl,mach                    */
    stc.l  ssr,@-r15    
    stc.l  gbr,@-r15                    
    sts.l  macl,@-r15                    
    sts.l  mach,@-r15                                                    
    stc.l  r0_bank,@-r15   /* ,r0〜r7をスタックに保存   */ 
    stc.l  r1_bank,@-r15
    stc.l  r2_bank,@-r15
    stc.l  r3_bank,@-r15
    stc.l  r4_bank,@-r15
    stc.l  r5_bank,@-r15
    stc.l  r6_bank,@-r15    
    stc.l  r7_bank,@-r15
    tst    r7,r7                 /* 割り込み発生時のコンテキストを判定  */  
    bf/s    _interrupt_from_int  /* 例外/割り込みハンドラならジャンプ   */
     add    #0x01,r7             /* 割り込みのネスト回数をインクリメント*/
    mov    r15,r1                /* スタックを入れ替え元のスタックポイ  */
    mov.l  _stacktop_k,r15       /* ンタを保存                          */
    mov.l  r1,@-r15            
#ifdef GHS_HOOK
	mov.l   r7,@-r15
	stc     spc,r0
	mov.l   r0,r5
	mov.l   _intevt,r0          /* 例外要因レジスタを取得              */
	mov.l   _interrupt_hook_dis,r2
	jsr     @r2
	mov.l   @r0,r4              
	mov.l   @r15+,r7
#endif
    mov.l  _intevt,r0            /* 例外要因レジスタを取得              */
    mov.l  @r0,r4              
    shlr2  r4                    /* 3ビット右シフトしオフセットを求める */
    shlr   r4                  
    mov.l  _int_plevel_table_k,r0 
    mov.l  @(r0,r4),r5           /* 割り込みの優先度を取得               */
    mov.l  _int_table_k,r0    
    mov.l  @(r0,r4),r2           /* 割り込みハンドラのアドレスを取得    */
    ldc    r2,r2_bank            /* バンク0に切り替えるためコピー       */    
    ldc    r5,sr                 /* これ以降割り込みを受け付ける。      */
    jsr    @r2                   /* 割り込みハンドラへ                  */
     nop
    mov.l  _mask_md_ipm_ret,r0
    ldc    r0,sr                 /* 割り込み禁止                           */
    stc    r7_bank,r7            /* 例外/割り込みのネスト回数をデクリメント*/
    dt     r7
    ldc    r7,r7_bank
    mov.l  _reqflg_k,r4          /* reqflgのチェック                       */
    mov.l  @r4,r1
    tst    r1,r1                 /* reqflgがFALSEならret_to_task_intに飛ぶ */
    bt/s   _ret_to_task_int      /* タスクに戻る                           */
     mov.l  @r15,r15             /* 戻り先がタスクなのでスタックを戻す     */
    xor    r0,r0
    bra    ret_int
     mov.l  r0,@r4               /* reqflgをクリア                   */
_interrupt_from_int:
#ifdef GHS_HOOK
	mov.l   r7,@-r15
	stc     spc,r0
	mov.l   r0,r5
	mov.l   _intevt,r0             /* 例外要因INTEVT2レジスタを取得    */
	mov.l   _interrupt_hook_dis,r2
	jsr     @r2
	mov.l   @r0,r4
	mov.l   @r15+,r7
#endif
    mov.l   _intevt,r0           /* 例外要因レジスタを取得           */
    mov.l   @r0,r4
    shlr2   r4                   /* オフセットを求める               */
    shlr    r4                   /* オフセットを求める               */    
    mov.l   _int_plevel_table_k,r0 
    mov.l   @(r0,r4),r5            /* 割り込みの優先度を取得           */
    mov.l   _int_table_k,r0        
    mov.l   @(r0,r4),r2            /* 割り込みハンドラのアドレスを取得 */
    ldc     r2,r2_bank             /* バンク0に切り替えるためコピー    */
    ldc     r5,sr                  /* これ以降割り込みを受け付ける。   */
    jsr     @r2                    /* 割り込みハンドラへ               */ 
     nop
    mov.l  _mask_md_ipm_ret,r0
    ldc    r0,sr                   /* 割り込み禁止                     */
    stc    r7_bank,r7              /* 例外/割り込みのネスト回数をデクリメント*/
    dt     r7
    ldc    r7,r7_bank
_ret_to_task_int:
    mov.l  @r15+,r7                /* 割り込み元に戻る                 */
    mov.l  @r15+,r6
    mov.l  @r15+,r5
    mov.l  @r15+,r4
    mov.l  @r15+,r3
    mov.l  @r15+,r2
    mov.l  @r15+,r1
    mov.l  _mask_md_bl_int,r0 
    ldc    r0,sr                   /* BL を1に                         */
    mov.l  @r15+,r0
    lds.l  @r15+,mach                
    lds.l  @r15+,macl        
    ldc.l  @r15+,gbr                       
    ldc.l  @r15+,ssr
    lds.l  @r15+,pr
    ldc.l  @r15+,spc
    rte
     nop
#ifdef GHS_STUB
_rom_interrupt:
	stc.l	ssr,@-r15
	stc.l	spc,@-r15
	mov.l	r0,@-r15
	mov.l	r1,@-r15
	mov.l	L._CpuException6,r1
	jmp	@r1
	mov	#6,r0

	.align	4
L._CpuException6:
	.data.l	_CpuExceptionHandler
#endif
    /*
     * 未登録の割込みが発生すると，その時の INTEVT,INTEVT2,SR,PC を
     * 引数にcpu_interrupt()を呼び出す．
     */   
    .global _no_reg_interrupt
_no_reg_interrupt:
    mov.l _intevt1,r0
    mov.l @r0,r4
#if defined(SH7709) || defined(SH7709A) || defined(SH7729R) || defined(SH7727) 
    mov.l _intevt2,r0    
    mov.l @r0,r5
#endif 
    stc   spc,r6
    stc   ssr,r7
    mov.l _cpu_interrupt_k,r1
    jsr   @r1
     nop
    .align  4
_stacktop_k:
    .long  STACKTOP            /* 非タスク独立部のスタックの初期値  */
_intevt:        
#if defined(SH7708) || defined(SH7750)    
    .long  INTEVT
#else
    .long  INTEVT2
#endif    
_int_table_k:    
    .long    _int_table       
_int_plevel_table_k:    
    .long    _int_plevel_table 
_reqflg_k:
    .long  _reqflg
_mask_md_ipm_ret:    
    .long  0x40000000 + MAX_IPM << 4
_mask_md_bl_int:    
    .long  0x50000000
_intevt1:        
    .long  INTEVT
#if defined(SH7709) || defined(SH7709A) || defined(SH7729R) || defined(SH7727) 
_intevt2:        
    .long  INTEVT2
#endif 
_cpu_interrupt_k:
    .long  _cpu_interrupt   
#ifdef GHS_HOOK
_interrupt_hook_dis:
	.long   _exception_hook
#endif

   
/*
 *  微少時間待ち
 */
	.globl _sil_dly_nse
_sil_dly_nse:
    mov.l  _sil_dly_tim1, r1
    add    r1, r4
    cmp/pl r4
    bt     _sil_dly_nse1
    rts
     nop
_sil_dly_nse1:            
    mov.l  _sil_dly_tim2, r1
    add    r1, r4
    cmp/pl r4
    bt     _sil_dly_nse1
    rts
     nop   
    .align 4
_sil_dly_tim1:
    .long  -SIL_DLY_TIM1    
_sil_dly_tim2:                         
    .long  -SIL_DLY_TIM2
