uARM 確認 (2)

ヤケクソ気味で socInit 手続きから呼び出されている cpuInit という手続きを確認。ARMv5TE なマニュアルを確認しなければならないのかどうか。
呼び出しは以下な形。

	e = cpuInit(&soc->cpu, ROM_BASE, vMemF, emulErrF, hyperF, &setFaultAdrF);

まず渡してる引数を確認してみます。ROM_BASE なマクロが以下。

#define ROM_BASE	0x00000000UL

vMemF は手続きですね。mmuTranslate という手続きの戻りと memAccess という手続きの戻りの論理積を戻している模様。mmuTranslate の戻りが 0 値なら終了なのかな。
emulErrF も手続きですね。接尾辞 F は function って意味なのかな。エラー処理みたいなことして最後に無限ループさせてます。hyperF も手続きですね。ちょっと気になったのですが手続き定義が以下な形です。

static Boolean hyperF(ArmCpu* cpu){

Boolean て何だ。手繰ってみるに以下な定義。

typedef unsigned char Boolean;

直下に true および false なマクロ定義もありました。

#define true	1
#define false	0

types.h にて定義な模様。最後の setFaultAdrF も手続きです。こちらもエラー処理なのかどうか。で、cpuInit 手続きですが少しづつ順に確認してみます。

	if(!TYPE_CHECK){
		emulErrF(cpu, "Type size error! CPU init aborted");
		return errInternal;
	}

	__mem_zero(cpu, sizeof(ArmCpu));

最初のマクロが以下。正に TYPE_CHECK ですね。

#define TYPE_CHECK ((sizeof(UInt32) == 4) && (sizeof(UInt16) == 2) && (sizeof(UInt8) == 1))

__mem_zero もなかなかにアレ。

void __mem_zero(void* ptr, UInt16 sz){

	UInt8* p = ptr;

	while(sz--) *p++ = 0;
}

UInt8 は unsigned char なマクロになってます。sz byte 分を 1byte づつ初期化、なんですね。ArmCpu 型な領域を初期化して続きが以下。

	cpu->CPSR = ARM_SR_I | ARM_SR_F | ARM_SR_MODE_SVC;	//start w/o interrupts in supervisor mode
	cpuPrvSetPC(cpu, pc);

ええと、ArmCpu 構造体の CPSR な属性の定義が以下なのですが

typedef struct ArmCpu{

	UInt32		regs[16];		//current active regs as per current mode
	UInt32		CPSR, SPSR;

レジスタ? と言いつつググッてみたら Current Program Status Register の略ですね。あと、SPSR は例外発生時に CPSR を退避とのこと。レジスタは 15 本ってあるけれど、ここでは 16 個ある形になってますね。あ、PC 含めで 16 本らしい。
以下なドキュメントに CPSR のフォーマットが出てますね。

なにでリセットしてるかというと

ここではおそらくビットを on にしてるので割り込みを無効にしてますね

  • ARM_SR_MODE_SVC
    • This supports high speed interrupt handling. Generally it is used for a single critical interrupt source in a system.
    • こっちのフォーマット記述はマクロと合致しますね
    • supervisor モード、ということで良いかな

次は cpuPrvSetPC という手続きを ArmCpu なオブジェクトと ROM_BASE な 0x0UL を渡しておられます。短いので引用してみます。

static _INLINE_ void cpuPrvSetPC(ArmCpu* cpu, UInt32 pc){
	cpu->regs[15] = pc &~ 1UL;
	cpu->CPSR &=~ ARM_SR_T;
	if(pc & 1) cpu->CPSR |= ARM_SR_T;
	else if(pc & 2) cpu->emulErrF(cpu, "Attempt to branch to non-word-aligned ARM address");
}

ええと、以下な記述が順にならんでるのかどうか。

  • 1UL をビット反転したものと pc のビット積を regs[15] に代入
    • 実際 pc は 0 なのでここでは 0 代入
  • CPSR から ARM_SR_T ビットを落とす
    • 反転させて & 取ってるからいいよね
  • pc の末端ビットが on なら CPSR の ARM_SR_T を立てる
  • そうでなくて末端の次のビットが on なら emulErrF 手続き呼び出し
    • これ、まだこの時点ではセットされてなかったりしますね
    • とは言え、どちらの分岐も通過はしないので無問題か

この手続き呼び出しに伴なう副作用は

  • cpu->regs[15] をゼロで初期化
  • cpu->CPSR から ARM_SR_T を落とす

という事になるのかどうか。そして次のブロックで引数で受け取った手続きを ArmCpu オブジェクトな属性に設定してますね。

	cpu->memF = memF;
	cpu->emulErrF = emulErrF;
	cpu->hypercallF = hypercallF;
	cpu->setFaultAdrF = setFaultAdrF;

で、icacheInit 手続きを呼び出しています。

	icacheInit(&cpu->ic, cpu, memF);

	return errNone;

この手続きの定義が以下。

void icacheInit(icache* ic, ArmCpu* cpu, ArmCpuMemF memF){

	ic->cpu = cpu;
	ic->memF = memF;

	icacheInval(ic);
}

引数設定して icacheInval 手続き呼び出してますね。この手続きは直上で定義されている模様。

void icacheInval(icache* ic){

	UInt8 i, j;

	for(i = 0; i < ICACHE_BUCKET_NUM; i++){
		for(j = 0; j < ICACHE_BUCKET_SZ; j++) ic->lines[i][j].info = 0;
		ic->ptr[i] = 0;
	}
}

あら、icache て何でしょ。あ、そもそも ArmCpu オブジェクトの ic 属性を渡していますね。icache 型の定義は以下。

typedef struct{

	struct ArmCpu* cpu;
	ArmCpuMemF memF;
	icacheLine lines[ICACHE_BUCKET_NUM][ICACHE_BUCKET_SZ];
	UInt8 ptr[ICACHE_BUCKET_NUM];

}icache;

ええと、icache 型の lines と ptr をゼロで初期化してるんですね。これで ArmCpu オブジェクトの初期化は完了な模様です。

とりあえず

この調子で socInit 手続きを読んでいくと ARMv5TE と pxa255 をどう組み合せているのかとか理解できるかも (ソフトウェア的に?)。とは言えいったんエントリ投入。