FPGA開発日記

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

ISSにシステムレジスタ読み書きの機能を実装する

MIPSのシステムレジスタ読み書きの機能を実装する

xv6のデバッグをしていて、何か動作がおかしいなと思っていたら、システムレジスタを定義していたものの、読み書きの動作を定義していなかった! そりゃ、うまくいかない。

github.com

とりあえず、システムレジスタの読み書きの仕組みだけ実装した。 例えば、割り込みが外部から発生したときは、このシステムレジスタを外から書き込むようにして、状態を保存させる。 まだ機能が不十分で、全てを実装できている訳ではないが。

    CSRWrite (SYSREG_ADDR_EPC, GetPC());

    Word_t cause;
    CSRRead (SYSREG_ADDR_CAUSE, &cause);
    cause &= ~(0x1f << 2);
    cause |= (CauseInt << 2);
    CSRWrite (SYSREG_ADDR_CAUSE, cause);

    CSRRead (SYSREG_ADDR_CAUSE, &cause);
    InfoPrint ("<Interrupt CAUSE = %08x>\n", cause);

とりあえず、xv6において割り込みが発生したときに、割り込み要因はこれで判定できるようになる。

trap(struct trapframe *tf)
{
  uint exccode = tf->cause & CAUSE_EXC;   // ← ここで実際に読まれているのは、C0のCAUSEレジスタの値
  if(exccode == EXC_SYSCALL){
    if(proc->killed)
...

ただし、これでもまだ十分ではないんだよなあ。どのIRQが発生したかについては、前述した 8259のモデルを作成しなければならない。

システムレジスタのテンプレート自動生成の仕組み

自分のISSでは、システムレジスタのテンプレートを作成すると、そこから自動的にC++のテンプレートを作成するような仕組みを作っている。

$sysreg_table[ 4] = Array[0x40, 'RW', 'Context',       Array[Array[31,23,'PTEBase','RW'],
                                                             Array[22, 4,'BadVPN2','R']]]
$sysreg_table[ 5] = Array[0x41, 'RW', 'ContextConfig', Array[Array[31, 0,'VirtualIndex','RW']]]
$sysreg_table[ 6] = Array[0x42, 'RW', 'UserLocal',     Array[Array[31, 0,'UserInformation','RW']]]
$sysreg_table[ 7] = Array[0x50, 'RW', 'PageMask',      Array[Array[29,13,'Mask','RW'],
                                                             Array[12,11,'MaskX','RW']]]
$sysreg_table[ 8] = Array[0x51, 'RW', 'PageGrain',     Array[Array[31,31,'RIE','RW'],
                                                             Array[30,30,'XIE','RW'],
                                                             Array[28,28,'ESP','RW'],

なんて風に書いておくと、

    union {
        struct {
            uint32_t dummy_0 : 4;
            uint32_t BadVPN2 : 19;
            uint32_t PTEBase : 9;
        } bit_Context;
        uint32_t Context;
    } Context;


    struct {
        uint32_t VirtualIndex;
    } ContextConfig;


    struct {
        uint32_t UserInformation;
    } UserLocal;

こんな風に、各システムレジスタのビットをビットフィールドを使って生成してくれる。たとえ間違ってビットフィールドを作っていたとしても生成できるし、そもそもビット位置を間違えることが無くなる。 (というか今回はこのフィールドの生成を間違えていたハマっていたのだけれども...)