090924

|


ツクバセラピーに行ってきました。5時半出発だとすっかり暗くなってきた。
夜明け前くらいの出発の方が気合いが入ってよい。永福登ると綺麗な朝焼け。



夜明け近辺の新宿線上りは絶景です。新宿は眺めてよし、呑んだくれてよし。

代々木のドコモビルもいい。

江北Jct.

C2。フェンスに反射する朝日が綺麗だ。

絶好の日和りだったのだけど、いろいろ大失敗。一本目は何度か引っぱっても らえる機会があったのだけど、なんかぜんぜんだめで、9秒も切れなかった。
走行終了後、ロガーデータを見てみると、ラップしかとれてない。あれ?と 思ってロガー分解して配線調べると...P-LAP線にコンパレータ入れたつもりが スピードセンサの線に入ってた...TT。
仕方ないので二本目はコネクタ交換して出走。しかしロガーの電池切れで データ採れず...。さらにはP-LAPの電池もなくなってきてタイムも見れなく なってしまった。
二本目はコースイン直後にS8群団がいたので、一周目からちょっとがんばり(僕 はいつも最初の3周は流し)。しかしどうもタイヤの滑りがひどい。3,4周で1コー ナーでズリズリ、最終でもズリズリになってしまい、怖くなってしまった。
二本目は荒れ場でずっと白旗、黄旗が出ている状況だったので、リアブレーキ の練習。後半になってやっとクリアになったのだけど、やっぱりタイヤがひど いので5分残して終了しました。

やっぱりタイヤ新品にしてくればよかった。でなければピストンのナラシにす ればよかった。まぁそれでも、もつ定食べれればそれでよしかな。
8:25 晴 362m 24.2℃ 65.5% 1017.1hPa
3枚67℃
13巻 12/8
Max 13500rpm
best 9.2

10:20 晴 431m 26.0℃ 59.5% 1016.3hPa
12巻


SH4A続き。

スレッドを実装してみよう。まずはカーネルモードのみ、レジスタバンク1のみ、
多重割込みなしの一番単純な実装。コンテキストスイッチするのは割込みのみ
で例外ではスイッチしない。

例外には3種類ある。フォールト、トラップ、アボートだ。フォールトは例外を
起こした命令の前で例外処理することで、その命令を実行させるので、コンテ
キストスイッチしてしてしまったら意味がない。トラップは例外命令を実行し
て例外処理に入るので、コンテキストスイッチしてもいい。アボートはどうに
もならないのでそこで終了だ。

割込みの場合は任意の命令と命令の隙間に入る。これはトラップが例外命令の
後処理をするか、割り込みの後処理をするかの違いくらい。

退避するレジスタはこのように設定した。これは実際の退避ルーチンで、
mov.l	Rn, @-Rmで退避しやすいよう(mov.l Rn, @Rm+はできない)に
してみた。

struct reg
{
  uint32_t pc;		// 0x
  uint32_t sr;		// 0x
  uint32_t pr;		// 0x
  // caller-saved(gcc) callee-saved(renesas)
  uint32_t mach;
  uint32_t macl;
  // callee-saved
  uint32_t sp;		// 0x
  uint32_t r14;		// 0x
  uint32_t r13;		// 0x
  uint32_t r12;		// 0x
  uint32_t r11;		// 0x
  uint32_t r10;		// 0x
  uint32_t r9;		// 0x
  uint32_t r8;		// 0x
  // caller-saved
  uint32_t r7;		// 0x
  uint32_t r6;		// 0x
  uint32_t r5;		// 0x
  uint32_t r4;		// 0x
  uint32_t r3;		// 0x
  uint32_t r2;		// 0x
  uint32_t r1;		// 0x
  uint32_t r0;		// 0x
} __attribute__((packed));

割り込みハンドラは(VBR+0x600)


	.section	.vector_interrupt, "ax"	// "A"llocate. e"X"ecute.
ここでr15にいきなり退避できるのは、この実装がカーネルモードのみ、バンク
1 のみと設定しているから。そうでなければどこのスタックを使うか吟味しないと
いけない。
	mov.l	r1,	@-r15

ここでcurrent_threadの退避領域にアクセスできるのは、多重割込みを禁止し
ているから。多重割り込みなら、レジスタはスレッド領域ではなく、スタック
に退避/復帰、復帰後のコンテキストスイッチなしにしないといけない。

	mov.l	.L_current_thread	r1
	mov.l	@r1,	r1
	add	#0x54, 	r1	// sizeof (struct reg)

P0,P3のMMUでアクセス領域なら、ここでTLBミスが発生する可能性がある。ここ
は例外がブロックされているのでTLBミスが発生すればリセットだ。今回はMMU
を使わないのでOK。

	mov.l	r0,	@-r1
	mov	r1,	r0
	mov.l	@r15+,	r1	// restore R1 and R15
	mov.l	r1,	@-r0
	mov.l	r2,	@-r0
	mov.l	r3,	@-r0
	mov.l	r4,	@-r0
	mov.l	r5,	@-r0
	mov.l	r6,	@-r0
	mov.l	r7,	@-r0
	mov.l	r8,	@-r0
	mov.l	r9,	@-r0
	mov.l	r10,	@-r0
	mov.l	r11,	@-r0
	mov.l	r12,	@-r0
	mov.l	r13,	@-r0
	mov.l	r14,	@-r0
	mov.l	r15,	@-r0
	sts.l	macl,	@-r0
	sts.l	mach,	@-r0
	sts.l	pr,	@-r0
	stc.l	ssr,	@-r0
	stc.l	spc,	@-r0
	// All register saved.
多重割り込みなしなので、全部の割り込みをブロックするように設定した
あとに例外を有効に。(この設定の場合、例外はプログラムの間違い以外では
起こらないので、理論的には有効にする必要はない)
	// Set IMASK and Clear BL (Disable all interrupt.)
	stc	sr,	r0
	mov.l	.L_SR_IMASK,	r1
	or	r1,	r0
	mov.l	.L_SR_BL,	r1	// r1 = 0x10000000
	neg	r1,	r1		// r1 = 0xf0000000
	add	#-1,	r1		// r1 = 0xefffffff
	and	r1,	r0
	ldc	r0,	sr

ここで個別の割り込みハンドラをディスパッチ。
	mov.l	.L_exception_interrupt	r0
	jsr	@r0
	 nop

スレッドのスケジューリング。
	mov.l	.L_thread_context_switch, r0
	jsr	@r0
	 nop

例外をブロックして新しいコンテキストにスイッチ。多重割り込みじゃないので
本来は例外をブロックしなくてよい。(ここに割り込んでくるものはないので)

	// Block exception
	stc	sr,	r0
	mov.l	.L_SR_BL,	r1	// r1 = 0x10000000
	or	r1,	r0
	ldc	r0,	sr
	// Restore all register.
	mov.l	.L_current_thread	r0
	mov.l	@r0,	r0
	ldc.l	@r0+,	spc
	ldc.l	@r0+,	ssr
	lds.l	@r0+,	pr
	lds.l	@r0+,	mach
	lds.l	@r0+,	macl
	mov.l	@r0+,	r15
	mov.l	@r0+,	r14
	mov.l	@r0+,	r13
	mov.l	@r0+,	r12
	mov.l	@r0+,	r11
	mov.l	@r0+,	r10
	mov.l	@r0+,	r9
	mov.l	@r0+,	r8
	mov.l	@r0+,	r7
	mov.l	@r0+,	r6
	mov.l	@r0+,	r5
	mov.l	@r0+,	r4
	mov.l	@r0+,	r3
	mov.l	@r0+,	r2
	mov.l	@r0+,	r1
	rte
	 mov.l	@r0+,	r0
	.align	2
.L_current_thread:
	.long	_current_thread
.L_exception_interrupt:
	.long	_exception_interrupt
.L_SR_IMASK:
	.long	0xf0
.L_SR_BL:
	.long	0x10000000
.L_thread_context_switch:
	.long	_thread_context_switch


プログラム側から明示的にコンテキストスイッチするのは、caller-savedは
既にこのdo_thread_switchを呼ぶ前にスタックに退避されているので、それ
以外を退避するだけでいい。コンテキストスイッチはRTE命令でするので、
スイッチした後はPCとSRをSPC,SSRに設定し、これをRTE命令で戻してもらう。


	/* void do_thread_switch (void) */
	/* Assume already interrupt disabled */
	/* Called from thread context */
FUNC (_do_thread_switch)
	mov.l	.L_current_thread	r0
	mov.l	@r0,	r0
	add	#0x34,	r0	// skip caller saved.
	// Save callee-saved registers.
	mov.l	r8,	@-r0
	mov.l	r9,	@-r0
	mov.l	r10,	@-r0
	mov.l	r11,	@-r0
	mov.l	r12,	@-r0
	mov.l	r13,	@-r0
	mov.l	r14,	@-r0
	mov.l	r15,	@-r0
	sts.l	macl,	@-r0
	sts.l	mach,	@-r0
	sts.l	pr,	@-r0
	stc.l	sr,	@-r0
	sts.l	pr,	@-r0	// PC

	mov.l	.L_thread_context_switch	r0
	jsr	@r0
	 nop

ここでコンテキストスイッチされたものは割り込みでスイッチされたものかも
しれないので、全レジスタを復帰する。ここで例外をブロックする必要も本当
はないのも前述の通り。
	// Block exception
	stc	sr,	r0
	mov.l	.L_SR_BL,	r1	// r1 = 0x10000000
	or	r1,	r0
	ldc	r0,	sr
	// Restore all register.
	mov.l	.L_current_thread	r0
	mov.l	@r0,	r0
	ldc.l	@r0+,	spc
	ldc.l	@r0+,	ssr
	lds.l	@r0+,	pr
	lds.l	@r0+,	mach
	lds.l	@r0+,	macl
	mov.l	@r0+,	r15
	mov.l	@r0+,	r14
	mov.l	@r0+,	r13
	mov.l	@r0+,	r12
	mov.l	@r0+,	r11
	mov.l	@r0+,	r10
	mov.l	@r0+,	r9
	mov.l	@r0+,	r8
	mov.l	@r0+,	r7
	mov.l	@r0+,	r6
	mov.l	@r0+,	r5
	mov.l	@r0+,	r4
	mov.l	@r0+,	r3
	mov.l	@r0+,	r2
	mov.l	@r0+,	r1
	rte
	 mov.l	@r0+,	r0

	.align	2
.L_current_thread:
	.long	_current_thread
.L_thread_context_switch:
	.long	_thread_context_switch
.L_SR_BL:
	.long	0x10000000


タイマ割り込みでスレッド切り替えのテスト。

## Starting application at 0xA9000000 ...
RAM data: 0xa9003a7c-0xa9003eec 1136byte
bss: 0xa9003eec-0xa900510c 4640byte
ohayo
Privilege-mode, bank 1, Exception disabled, FPU enabled, IMASK=0xf
md_thread_setup: [1] a90048c0-a90044c0 {a9004444}
INTC: fffffffe 1f000000
md_thread_setup: [2] a9004444-a9004044 {a9003fc8}
md_thread_create: [2]:test pc=a900023c sp=a9004444 stack=1024byte
thread_start: [2]
thread_priority: [1] pri 1->3 state = 0 (DOWN)
thread_context_switch: {a9004444}: sp=a9004874
thread_context_switch: switch 1->2: sp=a9004444 pc=a900023c
test_thread:1234abcd
hello 0
thread_context_switch: {a9003fc8}: sp=a9004410
thread_context_switch: switch 2->1: sp=a9004874 pc=a9001a44
mon> timer
mon> a900018c b0
tmu0_intr
thread_context_switch: {a9004444}: sp=a9004884
thread_context_switch: 1 preempted by 2
thread_context_switch: switch 1->2: sp=a9004410 pc=a9001caa
hello 1
thread_context_switch: {a9003fc8}: sp=a9004410
thread_context_switch: switch 2->1: sp=a9004884 pc=a9000900
a900018c b0
tmu0_intr
thread_context_switch: {a9004444}: sp=a9004884
thread_context_switch: 1 preempted by 2
thread_context_switch: switch 1->2: sp=a9004410 pc=a9001caa
hello 2