FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

MIPSのシステムレジスタをISSに実装する(1)

という訳で、MIPSのシステムレジスタISSに実装し始めた。といっても、中身は空っぽで、読み出しと書き込みの機構を接続する。

github.com

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;
}

ここは必要に応じてどんどん実装していく。まずは、システムレジスタへのアクセスがまともに動くようになった。