という訳で、MIPSのシステムレジスタをISSに実装し始めた。といっても、中身は空っぽで、読み出しと書き込みの機構を接続する。
MIPSでは、MFC0/MTC0という命令を使ってシステムレジスタ(コプロセッサ0)にアクセスする。この機構は、RISC-VのCSRへのアクセスの機構をそのまま利用している。
void InstEnv::MIPS_INST_MFC0 (Word_t inst_hex) { RegAddr_t rt_addr = ExtractRTField (inst_hex); RegAddr_t rd_addr = ExtractRDField (inst_hex); RegAddr_t sel_addr = ExtractBitField (inst_hex, 2, 0); Word_t csr_addr = ((rd_addr & 0x01FUL) << 4) | (0x07U & sel_addr); Word_t csr_val; if (m_env->CSRRead (csr_addr, &csr_val) == -1) { m_env->DebugPrint ("<Exception>\n"); // m_env->GenerateException (Except_IllegalInst); return; } m_env->GRegWrite (rt_addr, csr_val); } void InstEnv::MIPS_INST_MTC0 (Word_t inst_hex) { RegAddr_t rt_addr = ExtractRTField (inst_hex); RegAddr_t rd_addr = ExtractRDField (inst_hex); RegAddr_t sel_addr = ExtractBitField (inst_hex, 2, 0); Word_t csr_addr = ((rd_addr & 0x01FUL) << 4) | (0x07U & sel_addr); Word_t csr_val; m_env->GRegRead (rt_addr); if (m_env->CSRWrite (csr_addr, csr_val) == -1) { m_env->DebugPrint ("<Exception>\n"); // m_env->GenerateException (Except_IllegalInst); return; } }
CSRReadとCSRWriteによって、登録されたコプロセッサのレジスタにアクセスする機構を追加した。 これにより、xv6のスタートアップルーチンでも、コプロセッサにアクセスしている様子が確認できる。
swimmer_mips --binfile kernel --debug --out debug.log --debug_func --debug_gvar --init_pc 0x80100000 less debug.log ... <BSF_Global: 0x8010a228 vector146 <BSF_Global: 0x8010a228 vector191 <BSF_Global: 0x8010a228 vector103 <BSF_Global: 0x8010a228 vector11 <BSF_Global: 0x8010a228 vector14 <Finish loading global variable table> <CsrAddr = 00c0> <MIPS_Read_CSR(000000c0)> <Read_STATUS is called.> <csr_status = 0> 0 : [80100000] 40086000 : mfc0 r12,0x0c,0x0 Status=>03c77750 r08<=03c77750 1 : [80100004] 24090001 : addiu r09,r00,0x0001 r00=>00000000 r09<=00000001 2 : [80100008] 01294025 : or r08,r09,r09 r09=>00000001 r09=>00000001 r08<=00000001 3 : [8010000c] 01094026 : xor r08,r08,r09 r08=>00000001 r09=>00000001 r08<=00000000 4 : [80100010] 3508ff00 : ori r08,r08,0xff00 r08=>00000000 r08<=0000ff00 5 : [80100014] 3c091000 : lui r09,0x1000 r09<=10000000 6 : [80100018] 01094025 : or r08,r08,r09 r08=>0000ff00 r09=>10000000 r08<=1000ff00 <CsrAddr = 00c0> 7 : [8010001c] 40886000 : mtc0 r12,0x0c,0x0 r08=>1000ff00 Status<=40886000 8 : [80100020] 3c1d8051 : lui r29,0x8051 r29<=80510000 9 : [80100024] 27bdd6e0 : addiu r29,r29,0xd6e0 r29=>80510000 r29<=8050d6e0 10 : [80100028] 3c088010 : lui r08,0x8010 r08<=80100000 11 : [8010002c] 2508516c : addiu r08,r08,0x516c r08=>80100000 r08<=8010516c 12 : [80100030] 01000008 : jr r08 r08=>8010516c pc<=80100034 pc<=8010516c 13 : [80100034] 00000000 : sll r00,r00,0x00 r00=>00000000 <Func: main> ...
最初の"Status"システムレジスタの初期値はなんだこりゃ?って感じだが、これはRead_CSR_STATUSの中身が空っぽのため、ポインタがゴミを差していることによる。
int32_t CsrEnv::Read_STATUS (Word_t *data) { return 0; }
ここは必要に応じてどんどん実装していく。まずは、システムレジスタへのアクセスがまともに動くようになった。