MIPS(アセンブラ)＆名古屋のIoTは名古屋のOSで

演習で使用する主な MIPS 命令 - 2017年度 システムプログラミング
http://www.swlab.cs.okayama-u.ac.jp/~nom/lect/p3/concise-mips-instruction-set.html

MIPS のアセンブリ言語の命令
https://brain.cc.kogakuin.ac.jp/~kanamaru/lecture/MP/final/part04/node6.html

MIPSのレジスタ
www.hino.meisei-u.ac.jp/is/iga/lecture/arc/No5org.pdf

プログラミングノート - MIPS
http://milkpot.sakura.ne.jp/note/mips.html

【アセンブリ】システムコールsyscallの使い方【MIPS】
http://totutotu.hatenablog.com/entry/2014/11/13/【アセンブリ】システムコールsyscallの使い方【MIPS】

MIPSのまとめ - 九州大学
ocw.kyushu-u.ac.jp/menu/faculty/09/4/10.pdf

命令：マシンの言葉I
www.rs.kagu.tus.ac.jp/t_yama/ca003_1.pdf

CPU と機械語
http://www.cc.kyoto-su.ac.jp/~kbys/kiso/cpu/mips.html

CPU と機械語(2)
http://www.cc.kyoto-su.ac.jp/~kbys/kiso/cpu/mips2.html

CPU と機械語(3)
http://www.cc.kyoto-su.ac.jp/~kbys/kiso/cpu/mips3.html

CPU と機械語(4)
http://www.cc.kyoto-su.ac.jp/~kbys/kiso/cpu/mips4.html

􏰒􏰓􏰐􏰑􏰎􏰏􏰍􏰂􏰋􏰌􏰉􏰊􏰇􏰈􏰅􏰆􏰃􏰄􏰁􏰂􏰀􏰒􏰓􏰐􏰑􏰎􏰏􏰍􏰂􏰋􏰌􏰉􏰊􏰇􏰈􏰅􏰆􏰃􏰄􏰁􏰂􏰀アセンブリ言語例題解説
http://www.cc.kyoto-su.ac.jp/~kbys/kiso/test-autumn/mips.pdf

toppers-jsp/config/mips3/cpu_support.S
https://github.com/ryoon/toppers-jsp/blob/master/config/mips3/cpu_support.S

```
/*
 *  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
 *  Copyright (C) 2000-2003 by Industrial Technology Institute,
 *                              Miyagi Prefectural Government, JAPAN
 * 
 *  上記著作権者は，以下の (1)～(4) の条件か，Free Software Foundation 
 *  によって公表されている GNU General Public License の Version 2 に記
 *  述されている条件を満たす場合に限り，本ソフトウェア（本ソフトウェア
 *  を改変したものを含む．以下同じ）を使用・複製・改変・再配布（以下，
 *  利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，その適用可能性も
 *  含めて，いかなる保証も行わない．また，本ソフトウェアの利用により直
 *  接的または間接的に生じたいかなる損害に関しても，その責任を負わない．
 */

#define _MACRO_ONLY

#include "jsp_kernel.h"
#include "offset.h"

	.section .text
	.align 2

	.set noat
		/* atレジスタを利用したときにワーニングを出力しないよう指定 */
	.set noreorder

/*
 *  例外/割り込み出入口処理ルーチン（一般例外）
 *
 *  仕様：
 *  ・CPU例外ハンドラは、非タスクコンテキストで実行する。
 *  ・k0 レジスタを、割込み／例外ネストカウンタとして使用する。
 *  ・reqflg をチェックする前に割込みを禁止しないと、reqflg をチェック後に起動さ
 *    れた割込みハンドラ内でディスパッチが要求された場合にディスパッチされない。
 *  ・割込み許可／不許可の処理は、EXLビットを用いて行う。
 *    これは、呼出元のコンテキストの CPUロック状態を保存するためである。
 *    ただし、共通部に処理を移行する場合にはIEビットを用いて、割込み許可／不許可
 *    を実現する必要があるために、IEビットによる割込み許可／不許可に変更している
 *    事に注意。
 *    （例：遅延ディスパッチの処理に入る直前、タスク例外処理を呼出す直前）
 *
 *  C言語ルーチンでlong long型を使う場合はレジスタの待避／復元をdouble wordで行
 *  うべきだが、使用頻度が低いのと、出入口処理のオーバーヘッドを考えて、wordで待
 *  避／復元を行っている。将来的には待避するデータサイズをタスク属性で指定できる
 *  ようにする予定
 */

	.global general_exception
	.global join_interrupt_and_exception
		/* 関数呼出(proc_interrupt_sys)時に必要 */

general_exception:
	addi    sp, sp, -25*4
	sw      sp,  0*4(sp)		/* EXCSTACK構造体用(cpu_experr関数用) */
	sw      at,  1*4(sp)
	sw      v0,  2*4(sp)
	sw      v1,  3*4(sp)
	sw      a0,  4*4(sp)
	sw      a1,  5*4(sp)
	sw      a2,  6*4(sp)
	sw      a3,  7*4(sp)
	sw      t0,  8*4(sp)
	sw      t1,  9*4(sp)
	sw      t2, 10*4(sp)
	sw      t3, 11*4(sp)
	sw      t4, 12*4(sp)
	sw      t5, 13*4(sp)
	sw      t6, 14*4(sp)
	sw      t7, 15*4(sp)
	sw      t8, 16*4(sp)
	sw      t9, 17*4(sp)
	sw      gp, 18*4(sp)
	sw      fp, 19*4(sp)
	sw      ra, 20*4(sp)

	mfc0    a1, Status		/* a1 -> 例外処理で使う */
	mfc0    t1, EPC

	sw      a1, 21*4(sp)		/* Status */
	sw      t1, 22*4(sp)		/* EPC */

	mfhi    t2			/* 乗除算レジスタ HI の待避 */
	mflo    t3			/* 乗除算レジスタ LO の待避 */

	sw      t2, 23*4(sp)		/* HI */
	sw      t3, 24*4(sp)		/* LO */

	move	a0, sp			/* 例外ハンドラの引数設定 */
		/* 引数は、例外発生時のデータを退避したスタック領域へのポインタ
		   割込みコントローラのデータを含めると複雑になるため、
		   対象はMIPS3コアのレジスタ部分のみとする。 */

	PUSH_ICU_IPM			/* 割込みコントローラの割込みマスクの
					   待避マクロ(システム依存部で定義) */

	bgtz    k0, multipul_exception  /*  初段の例外と多重例外の判別 */
	addi    k0, k0, 1               /* ネストカウンタのインクリメント */

/* 初段の例外の場合 */
first_exception:
	la      t3, _stack_top		/* _stack_top は、システム依存部
					   (リンカスクリプト推奨)定義 */
					/* スタックポインタの減算(t3=t3-4)は、
					   _stack_top 設定時に行っているので、
					   ここでは不要 */
	sw      sp, (t3)		/* タスクスタックポインタの保存 */
	move    sp, t3			/* スタック切り替え */

	jal     proc_interrupt_and_exception	/* 割込みと例外の判別処理へ */
	nop

	/*  割込み禁止で戻ってくる  */
	la      t2, reqflg
	lw      t3, (t2)		/* t3 = reqflg */
	lw      sp, (sp)		/* スタック切り替え */
	beq     t3, zero, ret_to_task_int	/* ディスパッチ要求がない場合 */
	nop

	j       ret_int			/* 割込み／例外の出口処理へ */
	sw      zero, (t2)		/* reqflg のクリア */

/* 多重例外（多重割込み）の場合 (例外ハンドラの引数は既に a0 に設定済み) */
multipul_exception:
	jal     proc_interrupt_and_exception	/* 割込みと例外の判別処理へ */
	nop

/* ディスパッチャを呼ばずに単純に割込み元（例外発生元）に戻る場合 */
ret_to_task_int:
	POP_ICU_IPM			/* 割込みコントローラの割込みマスクの
					   復帰マクロ(システム依存部で定義) */

	lw      t0, 23*4(sp)		/* HI */
	lw      t1, 24*4(sp)		/* LO */

	mthi    t0			/* 乗除算レジスタ HI の復元 */
	mtlo    t1			/* 乗除算レジスタ LO の復元 */

/*  保留：long long型を使用した場合  */
	lw      t0, 21*4(sp)    	/* Status */
	lw      t1, 22*4(sp)		/* EPC */

	lw      at,  1*4(sp)
	lw      v0,  2*4(sp)
	lw      v1,  3*4(sp)
	lw      a0,  4*4(sp)
	lw      a1,  5*4(sp)
	lw      a2,  6*4(sp)
	lw      a3,  7*4(sp)

	/*
	 *  多重例外時なので、タスクスイッチがない場合なので、タスクコンテキスト
	 *  の割込みマスクが変更されている心配はない。
	 *  （ステータスレジスタは元の値をそのまま書き戻す）
	 */
	mtc0    t0, Status
	mtc0    t1, EPC

	lw      t0,  8*4(sp)
	lw      t1,  9*4(sp)
	lw      t2, 10*4(sp)
	lw      t3, 11*4(sp)
	lw      t4, 12*4(sp)
	lw      t5, 13*4(sp)
	lw      t6, 14*4(sp)
	lw      t7, 15*4(sp)
	lw      t8, 16*4(sp)
	lw      t9, 17*4(sp)
	lw      gp, 18*4(sp)
	lw      fp, 19*4(sp)
	lw      ra, 20*4(sp)

	addi    sp, sp, 25*4		/* ERET 命令は、直後の命令を実行しない
					   ので遅延スロットには入れられない。*/

	eret				/* 例外からの復帰 */
	nop

/*
 *  割込みと例外の判別処理関数
 *    以下のレジスタに値が代入済み
 *      a0 : 例外ハンドラの引数, a1 : ステータスレジスタ
 */
proc_interrupt_and_exception:
	addi    sp, sp, -4
	sw      ra, 0(sp)

	mfc0    a2, Cause
	andi    t2, a2, ExcCode_mask
	beq     t2, zero, proc_interrupt        /* 割込みと例外の判別 */
		/* ここから直接proc_interrupt_sysへ飛びたいが、届かない
		   可能性があるので、一度proc_interruptに飛ぶ。 */
	nop

/* 割込み以外の例外の処理 */
	la      t4, exc_table
         	              		/* a1 = Status  */
	ori     t5, a1, SR_EXL
	xori    t5, t5, SR_EXL		/* EXLビットクリア */
		/* 割込み以外の例外はCPUロック状態でも受け付けるので、CPUロック
		   状態を保存する必要がある。そのためIEビットは操作せずに、割り
		   込み禁止・許可はEXLビットを用いて実現する */
	add     t6, t4, t2		/* 例外コード対応アドレスの設定 */
	lw      t7, (t6)		/* C言語ルーチンの呼出アドレス取得 */
	jalr    t7			/* C言語ルーチン呼び出し */
	mtc0    t5, Status		/* 割込み許可 (EXLビット = 0) */

	mfc0    t0, Status
	ori     t0, t0, SR_EXL
	mtc0    t0, Status              /* 割込み禁止 (EXLビット = 1) */

	NOP_FOR_CP0_HAZARD		/* CP0ハザードのための時間稼ぎマクロ
					   (このマクロはシステム依存部定義) */

	j       join_interrupt_and_exception	/* 例外・割込みの合流地点へ */
	nop

/* 割込みの場合の処理 */
proc_interrupt:

/*
 *  割込みコントローラの多様性に対応するため、実装はシステム依存部で行う。
 *    実装方法は、
 *	マクロ（PROC_INTERRUPT_SYS）または、関数呼出(proc_interrupt_sys)
 *    とする。
 *
 *  ・呼出時にセットされている引数
 *	a1 : ステータスレジスタ
 *	a2 : 原因レジスタ
 *
 *  ・実装時には、raレジスタを破壊してはならない。
 *
 *  ・実装する具体的な処理の流れ：
 *	1. 割込み要因の判別
 *	2. 割込みマスク（コア、割込みコントローラ）の設定
 *	3. 割込み許可
 *	4. Ｃ言語ルーチンの呼出
 *	5. 割込み禁止
 *	6. 割込みコントローラの割込み要求のクリア
 *     (7. join_interrupt_and_exceptionに戻る。; 関数呼出の場合)
 */

#ifdef PROC_INTERRUPT_SYS
	PROC_INTERRUPT_SYS
#else /* PROC_INTERRUPT_SYS */
	j	proc_interrupt_sys
	nop
#endif /* PROC_INTERRUPT_SYS */

/* 例外・割込み処理の合流地点 */
join_interrupt_and_exception:
	addi	k0, k0, -1		/* ネストカウンタ ディクリメント */
	lw      ra, (sp)		/* ra を復元 */
	jr      ra			/* proc_interrupt_and_exeption の呼出元
					   に戻る */
	addi    sp, sp, 4

/*
 *  割り込みハンドラ/CPU例外ハンドラ出口処理
 *
 *  戻り先がタスクコンテキストでreqflgがセットされている場合のみ、ここにくる。
 *  ・k0 = 0、割込み禁止状態、汎用レジスタを保存した状態で呼び出すこと。
 *  ・t1にruntskの値を入れてからret_int_1にジャンプすること。
 */

ret_int:
	POP_ICU_IPM			/* 割込みコントローラの割込みマスクの
					   復帰マクロ(システム依存部で定義) */

	lw      t1, 21*4(sp)		/* Status */
	ori	t1, t1, SR_EXL		/* 割込み処理に入るときの、CPUロック
					   状態を保持したいので、割込み禁止は
					   EXLビットを用いて行う。 */
	mtc0    t1, Status		/* MIPS3コアの割込みマスクの復帰
					    + EXLビットによる割込み禁止 */

	la      t0, enadsp
	la      t3, runtsk
	lw      t2, (t0)		/* t2 = enadsp */
	lw      t1, (t3)		/* t1 = runtsk */
 	beq     t2, zero, ret_int_1	/* ディスパッチ禁止ならジャンプ */
	nop
	la      t4, schedtsk
	lw      t5, (t4)		/* t5 = schedtsk */
	beq     t1, t5, ret_int_1	/* runtsk = schedtsk ならジャンプ */
	nop

/* ディスパッチャを経由する場合の処理 (t1 = runtsk に注意) */
	/* ここから、割込み禁止／許可を、EXLビットを用いて実現する方法に変更 */
	mfc0	t0, Status
	ori	t0, t0, SR_EXL_IE
	xori	t0, t0, SR_EXL_IE	/* lock_cpu 相当 (割込み禁止)
					    + EXLビットクリア (割込み許可) */
	mtc0	t0, Status

	addi    sp, sp, -8*4		/* スクラッチレジスタの保存 */
	sw      s0, 0*4(sp)
	sw      s1, 1*4(sp)
	sw      s2, 2*4(sp)
	sw      s3, 3*4(sp)
	sw      s4, 4*4(sp)
	sw      s5, 5*4(sp)
	sw      s6, 6*4(sp)
	sw      s7, 7*4(sp)
					/* t1 = runtsk に注意  */
	sw      sp, TCB_sp(t1)		/* runtsk->sp = sp
					   (タスクスタックポインタの保存) */
	la      t2, ret_int_r

	j       dispatcher		/* ディスパッチャ呼び出し */
	sw      t2, TCB_pc(t1)		/* runtsk->pc = ret_int_r
					   (実行再開番地の保存) */

/*
 * 割込み・例外の出口処理
 *   ・ディスパッチャ処理において、t1 = runtsk となっていることに注意
 *   ・スタックポインタも設定済み
 */
/* ディスパッチャ呼び出し後のタスクコンテキストからの合流地点 */
ret_int_r:
	lw      s0, 0*4(sp)		/* スクラッチレジスタの復元 */
	lw      s1, 1*4(sp)
	lw      s2, 2*4(sp)
	lw      s3, 3*4(sp)
 	lw      s4, 4*4(sp)
	lw      s5, 5*4(sp)
	lw      s6, 6*4(sp)
	lw      s7, 7*4(sp)
	addi    sp, sp, 8*4

	mfc0	t0, Status
	ori	t0, t0, SR_EXL_IE	/* unlock_cpu 相当 (割込み許可)
					    + EXLビットセット (割込み禁止) */
	mtc0	t0, Status

/* ディスパッチャを経由しない場合の合流地点 (t1 = runtsk に注意) */
ret_int_1:

	/* タスク例外処理要求のチェック */
	lb      t2, TCB_enatex(t1)
	andi    t4, t2, TCB_enatex_mask /* t3 = runtsk->enatex  */
	beq     t4, zero, ret_int_2     /* タスク例外処理禁止の時、ジャンプ */
	nop

	lw      t5, TCB_texptn(t1)      /* t5 = runtsk->texptn */
	beq     t5, zero, ret_int_2	/* タスク例外要求が無い時、ジャンプ */
	nop

	mfc0	t0, Status
	ori	t0, t0, SR_EXL_IE
	xori	t0, t0, SR_EXL_IE	/* lock_cpu相当 (割込み禁止)
					    + EXLビットクリア (割込み許可) */
	mtc0	t0, Status

	jal     call_texrtn             /* タスク例外処理ルーチン(ターゲット非
					   依存部定義)の呼び出し */
	nop
		/* call_texrtn()(task.c)では、実際のタスク例外処理ルーチン呼び
		   出し前後で、unlock_cpu、lock_cpu処理を行っているので、状態は
		   保持される。 */

	mfc0	t0, Status
	ori	t0, t0, SR_EXL_IE	/* unlock_cpu 相当 (割込み許可)
					    + EXLビットセット (割込み禁止) */
	mtc0	t0, Status
	/* ここまでが、割込み禁止／許可を、EXLビットを用いて実現する方法 */

ret_int_2:
	/* レジスタの復帰 (Statusレジスタは、既に復元済み) */
	lw      t1, 22*4(sp)		/* EPC */
	mtc0    t1, EPC

	lw      t2, 23*4(sp)		/* HI */
	lw      t3, 24*4(sp)		/* LO */

	mthi    t2			/* 乗除算レジスタ HI の復元 */
	mtlo    t3			/* 乗除算レジスタ LO の復元 */

	lw      at,  1*4(sp)
	lw      v0,  2*4(sp)
	lw      v1,  3*4(sp)
	lw      a0,  4*4(sp)
	lw      a1,  5*4(sp)
	lw      a2,  6*4(sp)
	lw      a3,  7*4(sp)
	lw      t0,  8*4(sp)
	lw      t1,  9*4(sp)
	lw      t2, 10*4(sp)
	lw      t3, 11*4(sp)
	lw      t4, 12*4(sp)
	lw      t5, 13*4(sp)
	lw      t6, 14*4(sp)
	lw      t7, 15*4(sp)
	lw      t8, 16*4(sp)
	lw      t9, 17*4(sp)

	lw      gp, 18*4(sp)
	lw      fp, 19*4(sp)
	lw      ra, 20*4(sp)

	addi    sp, sp, 25*4

	eret				/* 割込み/例外処理からの復帰 */
	nop

/*
 *  タスクディスパッチャ
 *  ・dispatch は、k0 = 0、CPUロック(割込み禁止)状態で呼び出さなければならない。
 *  ・exit_and_dispatch は，k0 = 0、CPUロック(割込み禁止)状態で呼び出すのが原則
 *    しかし、カーネル起動処理のため，k0 = 1で呼び出した場合にも対応している。
 */

	.global dispatch
	.global exit_and_dispatch

/* タスクディスパッチャを明示的に呼び出す時 */
dispatch:
	addi    sp, sp, -13*4
	sw      at,  1*4(sp)		/* スクラッチレジスタの待避 */
	sw      s0,  2*4(sp)
	sw      s1,  3*4(sp)
	sw      s2,  4*4(sp)
	sw      s3,  5*4(sp)
	sw      s4,  6*4(sp)
	sw      s5,  7*4(sp)
	sw      s6,  8*4(sp)
	sw      s7,  9*4(sp)
	sw      gp, 10*4(sp)
	sw      fp, 11*4(sp)
	sw      ra, 12*4(sp)

	la      t0, runtsk
	la      t2, dispatch_r
	lw      t1, (t0)		/* t1 = runtsk */
	sw      sp, TCB_sp(t1)		/* runtsk->sp = sp */
	j       dispatcher
	sw      t2, TCB_pc(t1)		/* runtsk->pc = dispatch_r */

/* 現在実行中のコンテキストを捨てて、タスクディスパッチャを呼び出す時 */
exit_and_dispatch:
	move    k0, zero		/* ネストカウンタをクリア */

dispatcher:
	/* ここには CPUロック（割り込み禁止）で来ること */
	la      t0, schedtsk
	lw      t1, (t0)		/* t1 = schedtsk */
	beq     t1, zero, dispatcher_2	/* schedtsk が無ければ割込み待ちへ */
	nop

dispatcher_1:
	la      t0, runtsk
	sw      t1, (t0)		/* runtsk = t1 (= schedtsk)
					   (タスクスイッチの実行) */
	lw      t2, TCB_pc(t1)		/* 実行再開番地を取得する。
					   実行再開番地は以下の3通り
					     ・ディスパッチャの出口  dispatch_r
					     ・割込み／例外の出口    ret_int_r
					     ・タスク起動直後        activate_r
					   いずれの場合も t1=runtsk として呼び
					   出していることに注意。 */
	jr      t2			/* 実行再開番地へジャンプ */
	lw      sp, TCB_sp(t1)		/* スタックポインタを復元 */

	/*
	 *  実行すべきタスクが現れるまで待つ処理
	 *
	 *  ここでコンテキストを切り換えるのは，
	 *    ・ここで発生する割込み処理にどのスタックを使うかという問題の解決
	 *    ・割込みハンドラ内でのタスクディスパッチの防止
	 *  という二つの意味がある．
	 */ 
dispatcher_2:
	la	t2, runtsk
	sw	zero, (t2)		/* runtsk = NULL
					   これは、iget_id が、TSK_NONEを返す
					   場合に対応するため。*/

	la      sp, _stack_top		/* スタック切り替え */
					/* _stack_top は、システム依存部
					   (リンカスクリプト推奨)定義 */
	li      k0, 1			/* ネストカウンタ＝1 */

	/* ループ内で使う定数の準備 */
	la      t2, reqflg              /* reqflg のアドレス */
	li      t3, ~SR_ERL_EXL         /* Status の割込み関連ビット */
	li      t4, ~SR_IE              /* Status の割込み許可ビット */

dispatcher_3:
	mfc0    t1, Status
	and     t1, t1, t3		/* ERL, EXL ビットクリア */
	ori     t1, t1, SR_IE		/* IEビットセット */
	mtc0    t1, Status		/* 割込み許可 : unlock_cpu 相当 */
	and     t1, t1, t4		/* IEビットリセット */
	mtc0    t1, Status		/* 割込み禁止 : lock_cpu 相当 */

	NOP_FOR_CP0_HAZARD		/* CP0ハザードのための時間稼ぎマクロ
					   (このマクロはシステム依存部定義) */

	lw      t5, (t2)		/* t5 = reqflg */

	beq     t5, zero, dispatcher_3	/* ディスパッチ要求がなければループの
					   先頭へ */
	nop
	sw      zero, (t2)		/* reqflg = NULL (reqflgをクリア) */
	j       dispatcher		/* 実行再開番地の取得処理へジャンプ */
	move    k0, zero		/* ネストカウンタをクリア */

/*
 *  ディスパッチャ出口処理
 *  ・ディスパッチャ処理において、t1 = runtsk となっていることに注意
 *  ・スタックポインタも設定済み
 */
dispatch_r: 
	lw      at,  1*4(sp)		/* スクラッチレジスタを復帰 */
	lw      s0,  2*4(sp)
	lw      s1,  3*4(sp)
	lw      s2,  4*4(sp)
	lw      s3,  5*4(sp)
	lw      s4,  6*4(sp)
	lw      s5,  7*4(sp)
	lw      s6,  8*4(sp)
	lw      s7,  9*4(sp)
	lw      gp, 10*4(sp)
	lw      fp, 11*4(sp)
	lw      ra, 12*4(sp)
	addi    sp, sp, 13*4

	/* タスク例外処理要求のチェック */
	lb      t2, TCB_enatex(t1)
	andi    t4, t2, TCB_enatex_mask	/* t4 = runtsk->enatex */
	beq     t4, zero, dispatch_r_1	/* タスク例外処理禁止の時、ジャンプ */
	nop

	lw      t5, TCB_texptn(t1)	/* t5 = runtsk->texptn */
	beq     t5, zero, dispatch_r_1	/* タスク例外要求が無い時、ジャンプ */
	nop

	j       call_texrtn		/* タスク例外処理ルーチン(ターゲット非
					   依存部定義)の呼び出し */
	nop
		/* call_texrtn()(task.c)では、実際のタスク例外処理ルーチン呼び
		   出し前後で、unlock_cpu、lock_cpu処理を行っているので、状態は
		   保持される。 */

dispatch_r_1:
	jr      ra			/* dispatch 呼び出し元へ戻る */
	nop

/*
 *  タスク起動処理
 *  ・ディスパッチャ処理において、t1 = runtsk となっていることに注意
 *  ・スタックポインタも設定済み
 */

	.globl activate_r

activate_r:
	/* ここに来るときは、CPUロックになっている（IEビット = 0) */

	/* 割り込み許可の準備 */
	mfc0    t0, Status
	ori     t0, t0, SR_ERL_EXL_IE   /* xorを使うため、1度ビットセットする */
	xori    t0, t0, SR_ERL_EXL      /* ERL, EXLビットをクリア
					   (IEビットは残す)  */

	/* タスク関係の設定準備 */
					/* t1 = runtsk (ディスパッチャで設定) */
	lw      t2, TCB_tinib(t1)       /* t2 = runtsk->tinib */

	/* タスク起動番地の設定 */
	lw      t3, TINIB_task(t2)      /* t3 = runtsk->tinib->task */

	/* タスクへの引数（拡張情報）設定 */
	lw      a0, TINIB_exinf(t2)     /* a0 = runtsk->tinib->exinf */

	mtc0    t0, Status              /* unlock_cpu 相当 (割込み許可) */

	la      ra, ext_tsk             /* タスクからの戻り番地を設定 */

	j       t3                      /* タスク起動 */
	nop
```

toppers-jsp/config/mips3/exception_vector.S
https://github.com/ryoon/toppers-jsp/blob/master/config/mips3/exception_vector.S

```
/*
 *  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
 *  Copyright (C) 2000-2003 by Industrial Technology Institute,
 *                              Miyagi Prefectural Government, JAPAN
 * 
 *  上記著作権者は，以下の (1)～(4) の条件か，Free Software Foundation 
 *  によって公表されている GNU General Public License の Version 2 に記
 *  述されている条件を満たす場合に限り，本ソフトウェア（本ソフトウェア
 *  を改変したものを含む．以下同じ）を使用・複製・改変・再配布（以下，
 *  利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，その適用可能性も
 *  含めて，いかなる保証も行わない．また，本ソフトウェアの利用により直
 *  接的または間接的に生じたいかなる損害に関しても，その責任を負わない．
 */

#define _MACRO_ONLY

#include "jsp_kernel.h"

	.section ".exce_vec_map","xa"
		/* exce_vec_map セクションの記述は、1kbyte内に収める
		   こと。(0xbfc00000-0xbfc00400 の範囲内)
		   これは、0xbfc00400 からの領域に、init セクション
		   ならびに text セクションが記述されるため。*/

	.set noreorder

	.align 2

/*
 *  例外ベクタアドレスでの分岐処理 (BEV=1を想定)
 */

/*
 *  コールドリセット、ソフトリセット、NMI(Non Maskable Interrupt)
 *     ステータスレジスタのBEVビットに
 *         依存しない：0xbfc00000番地  (kseg1領域；キャッシュなし)
 */

	.global start	/* ここがエントリーポイント */

start:
reset_and_NMI:
	mfc0	k0, Status
	li	k1, SR_SR
	and	k1, k0, k1
	bne	k1, zero, NMI_exception
	nop

	/* コールドリセット時 */
	la	k1, reset
	jr	k1
	nop

	/* ソフトリセット、NMI 時 */
NMI_exception:
	la	k1, reset
	jr	k1
	nop

/*
 *  TLB不一致例外（JSPカーネルではTLB未使用）
 *      ステータスレジスタのBEVビットが
 *          1のとき：0xbfc00200番地  (kseg1領域；キャッシュなし)
 *          0のとき：0x80000000番地  (kseg0領域；キャッシュあり)
 */
	.org 0x200

TLB_miscompare_exception:
	move	a0, sp
	mfc0	a1, Status
	mfc0	a2, Cause
	la	k1, cpu_experr
	jr	k1
	nop

/*
 *  XTLB不一致例外（JSPカーネルではTLB未使用）
 *      ステータスレジスタのBEVビットが
 *          1のとき：0xbfc00280番地  (kseg1領域；キャッシュなし)
 *          0のとき：0x80000080番地  (kseg0領域；キャッシュあり)
 */
	.org 0x280

XTLB_miscompare_exception:
	move	a0, sp
	mfc0	a1, Status
	mfc0	a2, Cause
	la	k1, cpu_experr
	jr	k1
	nop

/*
 *  キャッシュエラー例外
 *      ステータスレジスタのBEVビットが
 *          1のとき：0xbfc00300番地  (kseg1領域；キャッシュなし)
 *          0のとき：0xa0000100番地  (kseg0領域；キャッシュあり)
 */
	.org 0x300

cashe_error_exception:
	move	a0, sp
	mfc0	a1, Status
	mfc0	a2, Cause
	la	k1, cpu_experr
	jr	k1
	nop

/*
 *  その他例外：例外/割り込み出入口処理ルーチン
 *  (MIPSアーキテクチャは割込みベクタテーブルを持たず、割込みも一般例外の
 *   一種として分岐する)
 *      ステータスレジスタのBEVビットが
 *          1のとき：0xbfc00380番地  (kseg1領域；キャッシュなし)
 *          0のとき：0x80000180番地  (kseg0領域；キャッシュあり)
 */

	.org 0x200 + 0x180	/* TLB不一致例外の0x180番地後ろに配置 */

other_exception:
	la	k1, general_exception
	jr	k1
	nop
```

 ### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
####  Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.