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 のフォーマットが出てますね。
なにでリセットしてるかというと
- ARM_SR_I
- Interrupt Enable IRQ (?)
- ARM_SR_F
- Interrupt Enable FIQ (?)
- FIQ って何でしょ
- Fast Interrupt reQuest とありますね
- This supports high speed interrupt handling. Generally it is used for a single critical interrupt source in a system とのこと
- http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0203ij/Cacbhjjj.html
ここではおそらくビットを 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 をどう組み合せているのかとか理解できるかも (ソフトウェア的に?)。とは言えいったんエントリ投入。